《第一行代码》读书笔记 -- 应用组件之 ContentProvider
《第一行代码》读书笔记(一)-- 平台架构 (第1章)
《第一行代码》读书笔记(二)-- 应用组件之 Activity (第2、4章)
《第一行代码》读书笔记(三)-- 应用组件之 Service (第10章)
《第一行代码》读书笔记(四)-- 应用组件之 BroadcastReceiver (第5章)
《第一行代码》读书笔记(五)-- 应用组件之 ContentProvider (第7章)
《第一行代码》读书笔记(六)-- 数据存储方案 (第6章)
《第一行代码》读书笔记(七)-- 多媒体资源 (第8章)
《第一行代码》读书笔记(八)-- 网络编程 (第9章)
第7章 跨程序共享数据
ContentProvider 主要用于不同程序之间实现数据共享的功能,同时保证被访问数据的安全。
目前,使用 ContentProvider 是 Android 实现跨程序共享数据的标准方式。
ContentProvider 有两种用法,一是访问其他程序中的数据,另一种是创建自己的 ContentProvider 让其他程序访问。
访问其他程序中的数据
对于应用程序来说,访问内容提供器中共享的数据,要借助 ContentResolver 类,可以通过 Context 中的 getContentResolver() 方法获取该类的实例。
可以借助以下方法对共享的数据进行 CRUD 操作:
Cursor query(@NonNull Uri uri,
@Nullable String[] projection,
@Nullable String selection,
@Nullable String[] selectionArgs,
@Nullable String sortOrder)
Uri insert(@NonNull Uri url,
@Nullable ContentValues values)
int update(@NonNull Uri uri,
@Nullable ContentValues values,
@Nullable String where,
@Nullable String[] selectionArgs)
int delete(@NonNull Uri url,
@Nullable String where,
@Nullable String[] selectionArgs)
查询联系人示例:
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.d(TAG, name + ": " + number);
}
cursor.close();
}
创建自己的内容提供器
新建一个类继承 ContentProvider 即可创建自己的内容提供器。
public class MContentProvider extends ContentProvider {
private static final int TABLE_DIR = 0;
private static final int TABLE_ITEM = 1;
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.wshunli.provider.demo", "table1", TABLE_DIR);
uriMatcher.addURI("com.wshunli.provider.demo", "table1/#", TABLE_ITEM);
}
// 初始化内容提供器时调用。
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
switch (uriMatcher.match(uri)) {
case TABLE_DIR:
// 查询 table1 表中的所有数据
break;
case TABLE_ITEM:
// 查询 table1 表中的单挑数据
break;
}
return null;
}
// 根据传入的 URI 返回相应的 MIME 类型。
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)) {
case TABLE_DIR:
return "vnd.android.cursor.dir/vnd.com.wshunli.provider.demo.table1";
case TABLE_ITEM:
return "vnd.android.cursor.item/vnd.com.wshunli.provider.demo.table1";
}
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
对于 URI 有两种,一种是以路径结尾表示期望访问表中所有数据:
content://com.wshunli.provider.demo/table
另一种以 id 结尾表示期望访问该表中拥有相应 id 的数据:
content://com.wshunli.provider.demo/table/1
1、对于 UriMatcher 匹配 URI
*
表示任意长度的字符,#
表示任意长度的数字。
2、对于返回 MIME 类型,分别使用
表示单行数据:android.cursor.item/
表示多行数据:android.cursor.dir/
其他 insert 、 delete 、 update 方法类似。
实现跨程序数据共享
首先实现自己的 ContentProvider :
public class DatabaseProvider extends ContentProvider {
public static final int BOOK_DIR = 0;
public static final int BOOK_ITEM = 1;
public static final int CATEGORY_DIR = 2;
public static final int CATEGORY_ITEM = 3;
public static final String AUTHORITY = "com.wshunli.provider";
private static UriMatcher uriMatcher;
private MyDatabaseHelper dbHelper;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
}
@Override
public boolean onCreate() {
dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// 查询数据
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder);
break;
case CATEGORY_DIR:
cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null, null, sortOrder);
break;
default:
break;
}
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// 添加数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
Uri uriReturn = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
case BOOK_ITEM:
long newBookId = db.insert("Book", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
break;
case CATEGORY_DIR:
case CATEGORY_ITEM:
long newCategoryId = db.insert("Category", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
break;
default:
break;
}
return uriReturn;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// 更新数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
int updatedRows = 0;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
updatedRows = db.update("Book", values, selection, selectionArgs);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
updatedRows = db.update("Book", values, "id = ?", new String[] { bookId });
break;
case CATEGORY_DIR:
updatedRows = db.update("Category", values, selection, selectionArgs);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId });
break;
default:
break;
}
return updatedRows;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 删除数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
int deletedRows = 0;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
deletedRows = db.delete("Book", selection, selectionArgs);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
break;
case CATEGORY_DIR:
deletedRows = db.delete("Category", selection, selectionArgs);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
deletedRows = db.delete("Category", "id = ?", new String[] { categoryId });
break;
default:
break;
}
return deletedRows;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
return "vnd.android.cursor.dir/vnd.com.wshunli.provider.book";
case BOOK_ITEM:
return "vnd.android.cursor.item/vnd.com.wshunli.provider.book";
case CATEGORY_DIR:
return "vnd.android.cursor.dir/vnd.com.wshunli.provider.category";
case CATEGORY_ITEM:
return "vnd.android.cursor.item/vnd.com.wshunli.provider.category";
}
return null;
}
}
注意 ContentProvider 需要在 Manifest 中声明才能使用。
<provider
android:name=".MContentProvider"
android:authorities="com.wshunli.provider.demo"
android:enabled="true"
android:exported="true" />
然后就是访问 ContentProvider 了:
private String newId;
// 添加数据
Uri uri = Uri.parse("content://com.wshunli.provider/book");
ContentValues values = new ContentValues();
values.put("name", "A Clash of Kings");
values.put("author", "George Martin");
values.put("pages", 1040);
values.put("price", 55.55);
Uri newUri = getContentResolver().insert(uri, values);
newId = newUri.getPathSegments().get(1);
// 查询数据
Uri uri = Uri.parse("content://com.wshunli.provider/book");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor. getColumnIndex("name"));
String author = cursor.getString(cursor. getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex ("pages"));
double price = cursor.getDouble(cursor. getColumnIndex("price"));
Log.d("MainActivity", "book name is " + name);
Log.d("MainActivity", "book author is " + author);
Log.d("MainActivity", "book pages is " + pages);
Log.d("MainActivity", "book price is " + price);
}
cursor.close();
}
// 更新数据
Uri uri = Uri.parse("content://com.wshunli.provider/book/" + newId);
ContentValues values = new ContentValues();
values.put("name", "A Storm of Swords");
values.put("pages", 1216);
values.put("price", 24.05);
getContentResolver().update(uri, values, null, null);
// 删除数据
Uri uri = Uri.parse("content://com.wshunli.provider/book/" + newId);
getContentResolver().delete(uri, null, null);
也就是将前面的内容结合起来。
参考资料
1、ContentProvider | Android Developers
https://developer.android.com/guide/topics/providers/content-providers
2、Android深入四大组件(五)Content Provider的启动过程 | 刘望舒的博客
http://liuwangshu.cn/framework/component/5-contentprovider-start.html
评论 (0)