前言
数据库是Android开发中最基本的数据保存方式,但由于数据库的私有性,我们无法对外提供或获取信息,当两个应用需要实现数据共享时,此时就需要本篇文章的主题——ContentProvider
1、Uri基础
在使用ContentProvider之前,先介绍下Uri基础,Uri的对于开发者来说应该并不陌生,开发中使用Uri之处有很多,如:AppLink、FileProvider等,他们的作用相同都是定位资源位置,不同的是此处定义的是数据库中的信息;
- Uri的四个组成部分:content://contacts/people/5
- schema:已由Android固定设置为content://
- authority:ContentProvider权限,在AndroidMenifest中设置权限
- path:要操作的数据库表
- Id:查询的关键字(可选字段)
- Uri匹配模式
Uri的匹配表示要查询的数据,对于单个数据查询,可直接使用Uri定位具体的资源位置,但当范围查询时就需要结合通配符的使用,Uri提供以下两种通配符:
- *:匹配由任意长度的任何有效字符组成的字符串
- #:匹配由任意长度的数字字符组成的字符串
content://com.example.app.provider/table2/* //多数据查询
content://com.example.app.provider/table3/#
content://com.example.app.provider/table3/6 //单数据查询
- Uri的转换
Uri uri = Uri.parse(“content://contacts/people/5")
- Uri创建
//通过将 ID 值追加到 URI 末尾来访问表中的单个行
Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
2、ContentProvider使用
ContentProvider一般配合数据库共同使用,实现对外共享数据的目的,所以它需要对数据库的增删改查操作,ContentProvider也为我们提供了相应的操作方法,使用时只需实现即可,下面按照使用步骤实现一个ContentProvider:
- 创建ContentProvider的子类,重写insert、update、query、delete、getType
- 添加UriMatcher 映射数据表
UriMatcher的作用是在使用Uri操作数据库时,根据发起请求的Uri和配置好的uriMatcher确定本次操作的数据表
static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH)
Static{
uriMatcher.addURI(AUTHORIY,”userinfo”,1) //添加userinfo表映射
uriMatcher.addURI(AUTHORIY,”userinfo/*”,2) //*表示匹配任意长度任意字符
uriMatcher.addURI(AUTHORIY,”userinfo/#”,3) //#匹配任意长度的的数字
}
- insert ():添加数据
public Uri insert(Uri uri,ContentValues contentValues){
long newId = 0;
Uri newUri = null;
switch (uriMatcher.match(uri)){
newId = dataBase.insert(…) //此处的newId表示插入数据的id
newUri = Uri.parse(content://authoriy/**table/newId)
}
return newUri;
}
使用细节:
- dataBase添加后返回添加的id,此时使用withAppendedId ()和id创建添加的Uri
- insert()最终返回的是本次新添加数据的newUri
- 使用 ContentUris.parseId() 可以从newUri中获取本次添加数据的_ID
- query():查询方法
ContentProvider的查询和数据库查询一样,支持条件查询和多数据查询,返回结果为查询Cursor实例
//当查询整个数据表时. Uri.parse(”content://com.book.jtm/userinfo")
dataBase.query(….)
//当查询具体一个数据. Uri.parse(”content://com.book.jtm/userinfo/123456”)
String id = uri.getPathSegments().get(1)
//调价查询时
dataBase.query(table, projection,”tel_number = ?”,new String[]{
id},null, null,sortOrder)
- ContentObserver
提到ContentProvider的使用就会想到ContentObserver,这里一起介绍下ContentObserver,采用观察者模式在存储的数据发生修改时自动触发回调,使用起来也很简单创建ContentObserver的实例完成注册即可:
val contentObservable = object : ContentObserver(handler){
override fun onChange(selfChange: Boolean, uri: Uri?) {
super.onChange(selfChange, uri)
val cursor = contentResolver.query(uri, arrayOf("_id","name"),null,null,null)
if (cursor != null && cursor.moveToFirst()) {
do {
Log.e("========", cursor.getInt(cursor.getColumnIndex("_id")).toString())
Log.e("========", cursor.getString(cursor.getColumnIndex("name")).toString())
}while (cursor.moveToNext())
}