Android:内容提供器(Content Provider)(一)
一、内容提供器简介
内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证数据的安全性。
与文件存储和 SharedPreferences 存储中的两种全局可读可写操作模式不同,内容提供器可以选择那一部分数据进行共享。
二、访问其他程序中的数据
内容提供器的用法一般有两种,一种是使用现有的Android系统的内容提供器来读取和操作相应程序中的数据,如Android系统中自带的电话簿、短信和媒体库等;另一种是创建自己的内容提供器,为我们的程序的数据提供外部访问的接口。
1.URI简介
内容URI为内容提供器中的数据建立了唯一标识符。它主要由 authority 和 path 组成。
authority主要是用于对不同的应用程序做区分的,为了避免冲突,都会采用程序包名的方式来命名,如:com.example.app.provider。
path则是用于对同一个应用程序不同的表做区分的,通常添加在authority后面,如 com.example.app.provider/table。
内容URI的标准格式:content://com.example.app.provider/table
URI的两种理解
第一种:URI与数据库
由于 ContentResolver 提供了实现CRUD的方法,因此其实现方式与数据库的操作方式类似,但并不完全相同。
如下两个URI:
content://com.example.app.provider/table1
content://com.example.app.provider/table2
从这两个URI中可以很清楚的知道,我们是要访问哪个程序中的哪张“表”的数据。在数据库中查数据,需要提供表名,而这里,我们需要提供的是URI。
上面的URI写法,我们可以知道从那个表查数据,如果想访问table1中ID为1的数据,则可以使用下面的方式
content://com.example.app.provider/table1/1
也可以使用*和#
*:匹配任意长度的任意字符
#:匹配任意长度的数字
总结一下:
content://com.example.app.provider/table1
匹配table1中的所有数据
content://com.example.app.provider/table1/1
匹配table1中ID为1的数据
content://com.example.app.provider/*
匹配任意表的内容URI
content://com.example.app.provider/table1/#
匹配table1中任意一行数据的内容URI
第二种:URI与URL
互联网URL由三部分组成:
1.http://:URL的协议,这部分是固定的。
2.www.sample.com:域名部分,对于要访问的网站,这部分也是固定的。
3.index.html:网站资源部分。如果要访问不同的资源,这部分是动态改变的。
ContentProvider 要求的URL与此类似,如:
content://com.example.app.provider/words
它也由三部分组成:
1.content://:这部分是Android的 ContentProvider 规定的,暴露 ContentProvider、访问 ContentProvider 的协议默认就是 content://。
2.com.example.app.provider:这部分是 ContentProvider 的 authority 。要访问指定的 ContentProvider 这个部分是固定的。
3.words:资源部分,当需要访问不同资源时,这部分是动态改变的。
Android 的 URI 所能表达的功能很丰富,如下:
content://com.example.app.provider/words:访问全部数据
content://com.example.app.provider/words/2:访问words数据中ID为2的记录
content://com.example.app.provider/words/2/detail/访问words数据中ID为2的记录的detail字段
虽然 ContentProvider 所操作的数据大部分都来自于数据库,但有时候这些数据也能来自文件、XML或者网络等其他存储方式。如:
content://com.example.app.provider/words/detail/
此时,URI指的是 words 节点下的 detail 节点。
2.ContentResolver 的用法
要想访问应用程序中的内容提供器中的共享数据,就一定需要借助 ContentResolver 类。
ContentResolver 中提供了一系列的方法用于对数据进行 CRUD 操作,如下:
insert():用于添加数据。
update():用于更新数据。
delete():用于删除数据。
query():用于查询数据。
虽然 ContentResolver 的操作方法与 SQLiteDatabase 的操作方法很相似,但还是不同的。因为 ContentResolver 中提供的 CRUD 操作,接受的不是表名,而是 URI ,也被成为内容 URI。
在得到内容URI字符串后,需要将其解析为 Uri 对象才可以做为参数传入。如下:
Uri uri = Uri.parse("content://com.example.app.provider/table");
现在我们就可以通过 uri 对象来查询 table 表中的数据了,如:
Cursor cursor = getContentResolver().query()
uri,
projection,
selection,
selectionArgs,
sortOrder);
其他操作与此类似。
3.ContentProvider
从上面可以知道,ContentResolver 负责操作数据,那么 ContentProvider 的作用则是暴露数据。两者的关系如下图:
无论是 ContentResolver 还是 ContentProvider,它们所提供的 CRUD 方法的第一个参数都是 URI,URI 是两者进行数据交换的标识。 ContentResolver 对指定的 URI 进行 CRUD 操作,但URI并不提供数据,这些操作委托给了URI对应的 ContentProvider 来实现。
因此:
当 A 应用调用 ContentResolver 的 insert() 方法时,实际上相当于调用了该 URI 对应的 ContentProvider(应用B提供) 的 insert() 方法。
当 A 应用调用 ContentResolver 的 update() 方法时,实际上相当于调用了该 URI 对应的 ContentProvider(应用B提供) 的 update() 方法。
当 A 应用调用 ContentResolver 的 delete() 方法时,实际上相当于调用了该 URI 对应的 ContentProvider(应用B提供) 的 delete() 方法。
当 A 应用调用 ContentResolver 的 query() 方法时,实际上相当于调用了该 URI 对应的 ContentProvider(应用B提供) 的 query() 方法。
这样就实现了 A 应用访问 B 应用的底层数据。