前言
作为四大组件之一,它的地位绝对不容许轻视的。但是我们在哪里有用到过他呢?其实很简单,你在使用app时,是不是经常的会询问你是否开启通讯录的访问,如果你同意了,这个时候ContentProvider
就发挥了他的作用。
目录
- Android必知必会的四大组件 -- Activity篇
- Android必知必会的四大组件 -- ContentProvider篇
- Android必知必会的四大组件 -- Broadcast Receiver篇
- Android必知必会的四大组件 -- Service篇
思维导图
使用方法
以下通过对通讯录的操作让读者来更清晰的了解。 但是共享的数据不应该被我们随意的更改,如果有这样的需要,把这些数据存储在本地,然后再进行这样的操纵更为合适,所以下方的演示代码只包含了查询的功能。不过因为调用外部的数据,一般来说需要权限申请。
我已经在Android工具包中已经集成了权限申请的工具类。
// 数据查询
try (Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, 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.e(TAG, name + " ;" + number);
}
} catch (Exception e) {
e.printStackTrace();
}
文件共享的基础
其实在ContentProvider
中使用的通信机制依旧是Binder
,而文件定位则是通过URI
的方式来完成,所以主讲的一部分内容就是URI
的格式解析。
URI
格式:[scheme:][//host:port][path][?query]
这一个URI
的格式,为了方便起见,我们直接拿一个域名来分析它。
》》例题《《
- scheme:
https
,也就是协议 - host:
juejin.im
,域名地址 - port:默认80,端口号
- path:
/user/5e2659e15188254d95242d4b
,文件路径/控制器路径 - query:比如
?userId=x&message=y
,就是我们javaWeb
中的一些请求数据。
当然在我们的ContentProvider
存在一定的偏差。
文件位置:content://com.clericyi.file/message/id
- scheme:
content://
,这是Android的固定路径 - authority:
com.clericyi.file
,也就是用于标示唯一的ContentProvider
- path:
message
,也就是对应的表名 - id:对应表中的数据
帮助工具
UriMatcher
这是一个内置的URI
工具,他一共只提供了两个开放方法addURI()
、match()
,这是一个用于帮助匹配ContentProvider
中URI
的方法,针对的是除去id
前半段匹配。
// 用法
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
String authority = "com.clericyi.file";
String path = "message";
int URI_CODE = 1;
// 将URI和URI_CODE关联
uriMatcher.addURI(authority, path, URI_CODE);
// 用于获取对应的URI_CODE
uriMatcher.match(Uri.parse("content://com.clericyi.file/message"))
ContentUris
同样是一个内置的工具类,提供的方法有parseId()
、appendId()
、withAppendedId()
、removeId()
,针对的就是id
Uri uri = Uri.parse("content://com.clericyi.file/messag");
// 连接id
uri = ContentUris.withAppendedId(uri, CODE);
// 去除id
uri = ContentUris.removeId(uri);
// 获取id
long num = ContentUris.parseId(uri);
ContentProvider代码流程导读
工作流程:
从上文中的电话簿号码查询入手
(1)获取一个ContentResolver,并调用query(),内部参数很多,基本和数据库查询的参数保持一致。
(2)在query()方法中会调用到acquireUnstableProvider(uri)的方法,而返回值IContentProvider,对应就是一个Binder机制
(3)内部通过对uri的一些解析,找得到对应的文件,然后转化成Cursor游标
(4)通过游标的滑动读取,就转化成了我们的数据
query()内部参数分析
- uri:位置暴露的唯一表示。
- projection:返回列(字段)
- selection:设置条件,相当于数据库中的where
- selectionArgs:和selection联合使用,用于替换selection中的 ?
- sortOrder:排列顺序,相当于数据库中的order by
全部参数使用实例:
contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI
, new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME}
, android.provider.ContactsContract.Contacts.DISPLAY_NAME + "=?"
, new String[]{"小易"}
, android.provider.ContactsContract.Contacts.DISPLAY_NAME + " DESC"); // 中间存在空格,默认为ASC,升序。
最后的话这片文章就不写关于联合Database的使用了,应该容易冗长,专门找了一篇文章给读者们拿来专门学习ContentProvider的使用。跳转链接
另外也算是我的一种突破,毕竟一天发了四篇博客,虽然两篇其实我只是重构了一下,但是着实还是有点累的。