第八章 Content Provider
第八章 Content Provider
在Android中推荐使用content provider方法在不同包之间共享数据
content provider可以被视为一个数据仓库 他如何存储数据与应用如何使用它无关。然而应用如何使用一致的编程接口来访问存储在它里面的数据却非常重要。Content provider的行为与数据库非常相似(可以查询它、编辑它的内容、添加或者删除内容)
与数据库不同的是:一个content provider可以使用不同的方式存储他的数据,数据可以被存储在数据库中、文件中、网络上
Content provider的种类:
Browser:存储浏览器数据,如浏览器书签、浏览器访问历史等
CallLog:存储通话数据,如未接电话、电话详情等
Contacts:存储通讯录详情
MediaStore:存储多媒体文件,如音频、视频、图片
Settings:存储设备的设置和偏好设置
除了许多内置的content provider以外,可以创建自定义的content provider
要查询一个content provider,需要以统一资源标识符URI的形式指定查询字符串,以及一个可选的特定行说明符
使用contenet provider:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jfdimarzio.contentproviders.MainActivity">
<TextView
android:text="ISBN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
tools:layout_constraintLeft_creator="1"
app:layout_constraintTop_toTopOf="@+id/activity_main"
android:layout_marginTop="16dp"
app:layout_constraintRight_toRightOf="@+id/activity_main"
tools:layout_constraintRight_creator="1" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text"
android:ems="10"
android:id="@+id/txtISBN"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
tools:layout_constraintLeft_creator="1"
app:layout_constraintTop_toBottomOf="@+id/textView"
android:layout_marginTop="8dp"
app:layout_constraintRight_toRightOf="@+id/activity_main"
tools:layout_constraintRight_creator="1"
app:layout_constraintBottom_toTopOf="@+id/textView2"
android:layout_marginBottom="8dp"
app:layout_constraintHorizontal_bias="0.46"
app:layout_constraintVertical_bias="0.100000024" />
<TextView
android:text="Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView2"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
tools:layout_constraintLeft_creator="1"
app:layout_constraintTop_toTopOf="@+id/activity_main"
android:layout_marginTop="142dp"
tools:layout_constraintTop_creator="1"
app:layout_constraintRight_toRightOf="@+id/activity_main"
tools:layout_constraintRight_creator="1" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text"
android:ems="10"
android:id="@+id/txtTitle"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
tools:layout_constraintLeft_creator="1"
app:layout_constraintTop_toBottomOf="@+id/textView2"
android:layout_marginTop="8dp"
app:layout_constraintRight_toRightOf="@+id/activity_main"
tools:layout_constraintRight_creator="1" />
<Button
android:text="Add Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnAdd"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
tools:layout_constraintLeft_creator="1"
app:layout_constraintTop_toBottomOf="@+id/txtTitle"
android:layout_marginTop="112dp"
app:layout_constraintRight_toRightOf="@+id/activity_main"
tools:layout_constraintRight_creator="1"
android:onClick="onClickAddTitle" />
<Button
android:text="Retrieve Titles"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnRetrieve"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
tools:layout_constraintLeft_creator="1"
app:layout_constraintTop_toBottomOf="@+id/btnAdd"
android:layout_marginTop="32dp"
app:layout_constraintRight_toRightOf="@+id/activity_main"
tools:layout_constraintRight_creator="1"
android:onClick="onClickRetrieveTitles" />
</android.support.constraint.ConstraintLayout>
package com.jfdimarzio.contentproviders;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
public class BooksProvider extends ContentProvider {
static final String PROVIDER_NAME = "com.jfdimarzio.provider.Books";
static final Uri CONTENT_URI = Uri.parse("content://"+ PROVIDER_NAME + "/books");
static final String _ID = "_id";
static final String TITLE = "title";
static final String ISBN = "isbn";
static final int BOOKS = 1;
static final int BOOK_ID = 2;
private static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);
uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);
}
//---for database use---
SQLiteDatabase booksDB;
static final String DATABASE_NAME = "Books";
static final String DATABASE_TABLE = "titles";
static final int DATABASE_VERSION = 1;
static final String DATABASE_CREATE =
"create table " + DATABASE_TABLE +
" (_id integer primary key autoincrement, "
+ "title text not null, isbn text not null);";
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db)
{
db.execSQL(DATABASE_CREATE);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
Log.w("Provider database",
"Upgrading database from version " +
oldVersion + " to " + newVersion +
", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS titles");
onCreate(db);
}
}
public int delete(Uri arg0, String arg1, String[] arg2) {
// arg0 = uri
// arg1 = selection
// arg2 = selectionArgs
int count=0;
switch (uriMatcher.match(arg0)){
case BOOKS:
count = booksDB.delete(
DATABASE_TABLE,
arg1,
arg2);
break;
case BOOK_ID:
String id = arg0.getPathSegments().get(1);
count = booksDB.delete(
DATABASE_TABLE,
_ID + " = " + id +
(!TextUtils.isEmpty(arg1) ? " AND (" +
arg1 + ')' : ""),
arg2);
break;
default: throw new IllegalArgumentException("Unknown URI " + arg0);
}
getContext().getContentResolver().notifyChange(arg0, null);
return count;
}
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
//---get all books---
case BOOKS:
return "vnd.android.cursor.dir/vnd.learn2develop.books ";
//---get a particular book---
case BOOK_ID:
return "vnd.android.cursor.item/vnd.learn2develop.books ";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
public Uri insert(Uri uri, ContentValues values) {
//---add a new book---
long rowID = booksDB.insert(
DATABASE_TABLE,
"",
values);
//---if added successfully---
if (rowID>0)
{
Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
getContext().getContentResolver().notifyChange(_uri, null);
return _uri;
}
throw new SQLException("Failed to insert row into " + uri);
}
public boolean onCreate() {
Context context = getContext();
DatabaseHelper dbHelper = new DatabaseHelper(context);
booksDB = dbHelper.getWritableDatabase();
return (booksDB == null)? false:true;
}
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
sqlBuilder.setTables(DATABASE_TABLE);
if (uriMatcher.match(uri) == BOOK_ID)
//---if getting a particular book---
sqlBuilder.appendWhere(
_ID + " = " + uri.getPathSegments().get(1));
if (sortOrder==null || sortOrder=="")
sortOrder = TITLE;
Cursor c = sqlBuilder.query(
booksDB,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
//---register to watch a content URI for changes---
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int count = 0;
switch (uriMatcher.match(uri)){
case BOOKS:
count = booksDB.update(
DATABASE_TABLE,
values,
selection,
selectionArgs);
break;
case BOOK_ID:
count = booksDB.update(
DATABASE_TABLE,
values,
_ID + " = " + uri.getPathSegments().get(1) +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""),
selectionArgs);
break;
default: throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}
package com.jfdimarzio.contentproviders;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClickAddTitle(View view) {
//---add a book---
ContentValues values = new ContentValues();
values.put(BooksProvider.TITLE, ((EditText)
findViewById(R.id.txtTitle)).getText().toString());
values.put(BooksProvider.ISBN, ((EditText)
findViewById(R.id.txtISBN)).getText().toString());
Uri uri = getContentResolver().insert(
BooksProvider.CONTENT_URI, values);
Toast.makeText(getBaseContext(),uri.toString(),
Toast.LENGTH_LONG).show();
}
public void onClickRetrieveTitles(View view) {
//---retrieve the titles---
Uri allTitles = Uri.parse(
"content://com.jfdimarzio.provider.Books/books");
Cursor c;
CursorLoader cursorLoader = new CursorLoader(
this,
allTitles, null, null, null,
"title desc");
c = cursorLoader.loadInBackground();
if (c.moveToFirst()) {
do{
Toast.makeText(this,
c.getString(c.getColumnIndex(
BooksProvider._ID)) + ", " +
c.getString(c.getColumnIndex(
BooksProvider.TITLE)) + ", " +
c.getString(c.getColumnIndex(
BooksProvider.ISBN)),
Toast.LENGTH_SHORT).show();
} while (c.moveToNext());
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jfdimarzio.provider.MainActivity">
<TextView
android:text="TextView"
android:layout_width="0dp"
android:layout_height="60dp"
android:id="@+id/contactName"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
android:layout_marginStart="63dp"
tools:layout_constraintLeft_creator="1"
app:layout_constraintRight_toRightOf="@+id/activity_main"
android:layout_marginEnd="63dp"
tools:layout_constraintRight_creator="1"
app:layout_constraintBottom_toTopOf="@+id/contactID"
android:layout_marginBottom="40dp"
tools:layout_constraintBottom_creator="1" />
<TextView
android:text="TextView"
android:layout_width="0dp"
android:layout_height="64dp"
android:id="@+id/contactID"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
android:layout_marginStart="63dp"
tools:layout_constraintLeft_creator="1"
app:layout_constraintRight_toRightOf="@+id/activity_main"
android:layout_marginEnd="63dp"
tools:layout_constraintRight_creator="1"
app:layout_constraintBottom_toBottomOf="@+id/activity_main"
android:layout_marginBottom="56dp"
tools:layout_constraintBottom_creator="1" />
<ListView
android:layout_height="0dp"
android:id="@android:id/list"
android:layout_width="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
app:layout_constraintTop_toTopOf="@+id/activity_main"
tools:layout_constraintTop_creator="1"
app:layout_constraintRight_toRightOf="@+id/activity_main"
app:layout_constraintBottom_toTopOf="@+id/contactName"
android:layout_marginBottom="5dp"
tools:layout_constraintBottom_creator="1" />
</android.support.constraint.ConstraintLayout>
package com.jfdimarzio.provider;
import android.Manifest;
import android.app.ListActivity;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MainActivity extends ListActivity {
final private int REQUEST_READ_CONTACTS = 123;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
REQUEST_READ_CONTACTS);
} else{
ListContacts();
}
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_READ_CONTACTS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
ListContacts();
} else {
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void PrintContacts(Cursor c)
{
if (c.moveToFirst()) {
do{
String contactID = c.getString(c.getColumnIndex(
ContactsContract.Contacts._ID));
String contactDisplayName =
c.getString(c.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
Log.v("Content Providers", contactID + "," +
contactDisplayName);
//---get phone number---
//int hasPhone = c.getInt(c.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
Cursor phoneCursor =
getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " +
contactID, null, null);
while (phoneCursor.moveToNext()) {
Log.v("Content Providers",
phoneCursor.getString(
phoneCursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER)));
}
phoneCursor.close();
} while (c.moveToNext());
}
}
protected void ListContacts(){
Uri allContacts = Uri.parse("content://contacts/people");
Cursor c;
CursorLoader cursorLoader = new CursorLoader(
this,
allContacts,
null,
null,
null,
null);
c = cursorLoader.loadInBackground();
PrintContacts(c);
String[] columns = new String[]{
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts._ID};
int[] views = new int[]{R.id.contactName, R.id.contactID};
SimpleCursorAdapter adapter;
adapter = new SimpleCursorAdapter(
this, R.layout.activity_main, c, columns, views,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
this.setListAdapter(adapter);
}
}