时间过得真快, 上一篇关于 ContentProvider 的笔记还是 2015 年的时候, 之后就没有用过 ContentProvider 了, 有些东西都忘了, 而且关于自定义 ContentProvider 和 greendao 的内容比较少, 这里再重新整理一遍;
这里使用 greendao 框架存储数据, 不同点就是 SQLiteDatabase 对象是通过 greendao 提供的 getWritableSQLiteDatabase 方法来获取到的;
正文
继承 ContentProvider, 来实现跨进程的数据库访问; 继承的子类需要在 AndroidManifest.xml 中进行配置;
1 2 3 4 |
<provider android:exported="true" android:name="com.mxguo.db.ContactContentProvider" android:authorities="com.mxguo.contact.cp" /> |
- android:exported 是否可由其它应用调用
- android:name 子类的路径
- android:authorities 自定义的 uri
下面的例子中实现了一个查询:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
public class ContactContentProvider extends ContentProvider { private static final String TAG = "ContactContentProvider"; private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { sUriMatcher.addURI("com.mxguo.contact.cp", null, 1); } private SQLiteDatabase db; @Override public boolean onCreate() { db = ContactManager.getInstance(getContext()).getWritableSQLiteDatabase(); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (db == null) { db = ContactManager.getInstance(getContext()).getWritableSQLiteDatabase(); } if (sUriMatcher.match(uri) == 1) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(ContactDBInfo.TABLENAME); return qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); } else { return null; } } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues contentValues) { return null; } @Override public int delete(Uri uri, String s, String[] strings) { return 0; } @Override public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { return 0; } } |
使用 ContentResolver 调用自定义 ContentProvider 提供的方法
获取ContentResolver对象:
Context调用getContentResolver()方法返回ContentResolver对象
通过该对象调用insert,delete,update,query等方法
调用方法的第一个参数(Uri)为 ContentProvider 注册配置时的Uri。
例:getContentResolver().insert( Uri . parse( "content://com.mxguo.contact.cp" ),contentValue);
ContentResolver对象调用方法,事实上对应调用的是该Uri对应的ContentProvider中的对应方法
使用 ContentObserver 监听 ContentProvider 对应数据的改变
自定义 ContentObserver 的子类响应 ContentProvider 的变化;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class ContactObserver extends ContentObserver { private static final String TAG = "ContactObserver"; private Handler handler; public ContactObserver(Handler handler) { super(handler); this.handler = handler; } @Override public void onChange(boolean selfChange) {// 接收到变化后调用 PFLog.i(TAG, "onChange"); super.onChange(selfChange); if (handler != null) { handler.sendEmptyMessage(3455);// 使用构造参数传入的 handler 将变化传递出去, 在 handleMessage 方法中处理 } } } |
注册变化监听
1 |
getContentResolver().registerContentObserver(Uri.parse("com.mxguo.contact.cp"), false, new ContactObserver(workHandler)); |
通知 ContentProvider 数据变化
1 |
context.getContentResolver().notifyChange(Uri.parse("com.mxguo.contact.cp"), null); |
notifyChange 之后, 对这个Uri注册了监听的 ContentObserver 的 onChange 方法将被回调;
补充 UriMatcher
用来判断接收到的 uri 是否包含在 UriMatcher 中预设的 uri 之中;
方法
- addURI(String authority, String path, int code) 添加的 uri, 第三个参数 code 作为返回值 .match(uri) 的返回值
- match(Uri uri) 匹配的话, 返回 code
Uri
Uri person = ContentUris.withAppendedId("content://contacts/people", 45);
等价 content://contacts/people/45
Uri 中的方法 String getLastPathSegment () 返回路径中的最后一个片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { sUriMatcher.addURI("com.mxguo.provider", "contact", 1); sUriMatcher.addURI("com.mxguo.provider", "contact/#", 2);// # 匹配数字 sUriMatcher.addURI("com.mxguo.provider", "contacts/*", 3);// * 匹配任意文本 } int match = sURIMatcher.match(url); switch (match) { case 1: break; case 2: break; case 3: break; } |
0 Comments