引言
在安卓安全模型中,一个应用程序不能够直接去访问(读或写)另一个应用程序的数据,每个应用程序都有其自己的带id的结构化数据,自己的文件夹和私有的内存区域,ContentProvider是在这些应用程序间件共享数据。ContentProvider是一组包裹在标准的API下的读写操作。应用程序都必须注册为数据提供者才能共享数据,其它的应用程序能够通过固定的API去读写这些数据,所以ContentProvider严格遵守CRUD原则。
常见的实用ContnentProvider的案例有读取联系人方式、读取多媒体信息、以及其它的应用程序数据,同时也允许这些应用程序增删改查这些数据。

上图示意了ContentProvider是如何工作的,App1储存它的数据到其自己的数据库并且提供提供一个provider,另一个应用程序App2通过这个共享出来的provider曲获取App1的数据。ContentProvider是一种简单抽象的接口,使用了标准的insert(),query(),update(),delete()方法来获取和更新数据,可见实现一个ContentProvider是非常简单的。
每个ContentProvider都会被冠以content://字符串开头的作为特殊标识的URI,这是用来区分不同的应用程序的。
如何定义一个ContentProvider
作为安卓最重要的组建之一,要定义一个ContentProvider我们主要有如下步骤:
- 建立一个继承自ContentProvider的类
- 定义一个特殊的URI
- 实现所有的insert(), update(), query(), delete(), getType().方法
- 在AndroidManifest.xml中去声明
定义URI:
一个ContentProvider的URI定义的时候主要包括四部分.
比如:content://authority/path/id
content:// 所有的ContentProvider的URI定义都要以它打头
‘authority’ ContentProvider实现的时候的包名路径
‘path’ 这是一个虚拟的路由用来标识App下的某些数据的映射
‘id’ 可选字段,用来标识数据中的某一条信息
增加新的纪录:
增加一条心得纪录到数据库我们需要复写ContentProvider的insert()方法。调用者必须要指定ContentProvider的URI和想要传的值,但是不必传ID。成功插入的花会返回URI和新插入id的值。
比如:如果我们插入一条记录到content://com.example/sample,那么会返回content://com.example/sample/1。
更新纪录:
通过ContentProvider更新一条或多条数据,我们首先需要指定Content Provider的URI,通过update()方法去更新。可以通过指定id去更新某一条数据,但是如果要更新多条数据,就必须要传入selection参数,表示哪些行要被改变。该方法会返回影响的行数。
删除记录:
删除一条或多条数据和更新数据非常类似,我们需要指定id或者selection来进行删除。Content Provider的delete()方法会返回删除的记录的条数。
通过ContentProvider查询记录:
要通过ContentProvider去查询数据我们需要复写query()方法,这个方法有多个参数,可以通过projection参数指定列,通过selection指定筛选标准,还可以指定sortOrder,如果不指定projection,指针的所有列的值都会返回,如果不指定排序,那么会返回数据库中查询出来的默认排序。
getType()方法:
该方法用来处理指定URI后的MIME类型数据的请求,我们可以使用vnd.android.cursor.item或者vnd.android.cursor.dir/。 vnd.android.cursor.item用来指定某一个项目,而另一个用来指定所有的文件.
在AndroidManifest.xml中注册ContentProvider
作为四大组件之一,要使用的时候当然得在AndroidManifest.xml中去注册。
这里authorities是用来获取ContentProvider的,一般使用该类的路径。
一个例子
决定动手写一个ContentProvider的例子,我们这个例子包含两个Application,一个应用用来生成数据,另外一个应用用来获取前一个应用生成的数据。
共享数据的应用
第一个产生数据的应用很简单,就输入一个名字然后存到sqlite的db里面,成功就提示插入成功,同时可以点击查询按钮获取已经存好的姓名列表。新建一个名叫gordon_database的数据库,新建表names,拥有id和name两列值。
应用ContentProvider的URI是rawe.gordon.com.understandcontentprovider.provider.GordonContentProvider/gordon,首先来看看布局:
然后是我们的测试Activity:
最关键的ContentProvider
AndroidManifest.xml中声明:
好了,就是这么简单,当然有几个参数要注意一下,我们在manifest.xml中声明的authorities一定要和我们定义的类中的AUTHORITY一致,不然会抛出异常的。
演示一下,首先是输入界面:

新加一个名字:

查询我们已经插入的数据:

好了,到此一个最简单的插入和查询的ContentProvider写好了,也许你会说,这并没有什么卵用,我用Preference分分钟也搞定,存数据嘛,我有一万种方法。好了,的确如此,但是ContentProvider还可以给别的共享数据,当然是首先我们的App要允许啊,这个可以通过exported属性来设置,默认是false,那么我们把它置为true就可以了。
用别人的数据的应用
首先上布局:
我们使用LoaderManager来查询:
最重要的是我们要知道别的App的export出来的schema,这样才能正常的增删改查,同时也得知道数据结构是怎样的,列名是什么。
好了,来看看结果:

总结
使用ContentProvider还是很好的,可以很方便的玩转数据,复杂的操作只是在现在的基础上进行改进就行了,好了,写到这,如果想要试用ContentProvider,可以考虑从我下面的git地址去拷贝一份吧。
不想敲代码就到我的git来拉一下吧~https://github.com/gordon-rawe/understandContentProvider