ContentProvider主要用于不同的应用程序之间实现数据共享,不同于SharePreferences存储和文件存储有两种全局可读写方式进行的数据共享,ContentProvider可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险。且后两者的全局可读写的操作模式已经在Android4.2版本之后被官方废弃,目前使用ContentProvider是Android实现跨程序共享数据的标准方式。
技术名称 | 跨程序数据共享模式 | 现状 |
---|---|---|
ContentProvider | - | Android官方推荐 |
SharePreferences存储 | 设置MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE模式进行共享 | 跨程序数据共享模式在Android4.2后被官方废弃 |
文件存储 | 设置MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE模式进行共享 | 跨程序数据共享模式在Android4.2后被官方废弃 |
内容提供器应用场景:
- 读取系统通讯录;
- 读取短信;
- 访问媒体库等等。
📃 访问数据介绍
ContentProvider有两种用法:读取别人的和自己开放一个让别人读取。本节主要讲解如何访问别人程序的ContentProvider。
对于每一个应用程序来说,如果想要访问ContentProvider中共享的程序,就一定要借助ContentResolver
(内容解析器)类,可以通过Context中的getContentResolver()
的方法获得该类的实例。
ContentResolver中提供了一系列的方法用于对数据进行增删改查操作:
方法 | 说明 |
---|---|
insert() | 添加数据 |
update() | 更新数据 |
delete() | 删除数据 |
query() | 查询数据 |
ContentResolver的这四个增删改查方法与SQLiteDatabase的增删改查方法大体相似,只是接收参数上有些不同:
SQLiteDatabase的增删改查方法是以接收表名为参数(注意:非数据库名)的,而ContentResolver是以接收Uri为参数,而这个Uri参数被称为:内容URI。
内容URI给ContentProvider中的数据建立了唯一的标识符,它由两个部分组成:authority
和path
:
-
authority是为了对不同的应用程序做区分用的,一般采用包名的命名方式。比如某个应用包名是:
com.example.app
,则对应的authority可以命名为com.example.app.provider
; -
而path则是用于对同一应用程序中不同的表做区分的,通常添加到authority后面。
假定某个程序的数据库存在两张表:table1和table2,我们想要访问这两个表,内容URI可以这么写:com.example.app.provider/table1
和com.example.app.provider/table2
。不过,这种写法还不够清晰明确,我们还需要加个协议声明,所以写法又变成了这样:
content://com.example.app.provider/table1
content://com.example.app.provider/table2
以上也是内容URI最标准的写法,这种写法清晰明确的表明了我们想要访问哪个程序的哪张表。所以如果ContentResolver不用Uri为参数而单单是表名的话,系统是不知道我们想要访问哪个程序的哪张表的。
📝 小结一下:
- 我们想要访问数据就要用要借助
ContentResolver
类实例,该实例通过Context中的getContentResolver()
获得; ContentResolver
下包含增删改查四个方法,与SQLiteDatabase类类似;ContentResolver
中的增删改查方法是以内容URI为参数的。
🏃 访问数据步骤
1.将内容URI解析成Uri对象
我们要访问哪个应用程序的数据,就要得到相应的内容URI字符串。单单是字符串是不够的,因为系统不能读懂,所以我们还要把它解析成一个uri对象:
val uri = Uri.parse("content://com.example.app.provider/table1")
2.进行对应操作
有了Uri对象后,接下来直接在活动中获得ContentResolver
类实例,并使用对应的增删改查方法就行了。
1.查询数据 query()
方法:
val cursor = contentResolver.query(
uri,
projection,
selection,
selectionArgs,
sortOrder
)
五个参数的详细说明:
参数名称 | 对应SQL部分 | 描述 |
---|---|---|
uri | from table_name | 指定查询某个应用程序下的某一张表 |
projection | select column1,column2 | 指定查询的列名 |
selection | where column = value | 指定where的约束条件 |
selectionArgs | - | 为where中的占位符提供具体的值 |
sortOrder | order by column1,column2 | 指定查询结果的排序方式 |
查询完成后返回一个Cursor
对象给cursor实例,读取的思路和之前数据库的读取差不多————都是通过不断移动游标位置来遍历所有的表行,代码如下所示:
while (cursor!!.moveToNext()) {
val column1 = cursor.getString(cursor.getColumnIndex("column1"))
val column2 = cursor.getString(cursor.getColumnIndex("column2"))
}
cursor.close()
掌握了最难弹的查询方法后,剩下的增加、修改、删除操作就更不在话下了。
2.添加数据的 insert()
方法:
val values = contentValuesOf("column1" to "text","column2" to 123)
contentResolver.insert(uri,values)
这里没啥好说的,首先组装数据,再把它作为参数放到insert()
方法里去。
3.更新数据的 update()
方法:
如果我们想更新这条刚添加的数据,例如把column1的值清空,就使用update()
方法
val values = contentValuesOf("column1" to "")
contentResolver.update(uri,values,"column1 = ? and column2 = ?",arrayOf("text","1"))
值得注意的是,这里使用了selection
和selectionArgs
两个参数作为约束条件,避免其他行受到影响。
4.删除数据delete()
方法:
同样也使用了约束条件:
contentResolver.delete(uri,"column2 = ?",arrayOf("1"))
-
2020年7月25日 星期六 下午1:26