《第一行代码》读书笔记(五)

wshunli
2018-06-03 / 0 评论 / 5 阅读 / 正在检测是否收录...

《第一行代码》读书笔记 -- 应用组件之 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

评论 (0)

取消