文章目录
关于ContentProvider
ContentProvider,被称为内容提供者,通过Binder向其他组件以及其他应用提供数据。以某种Uri的形式对外提供数据,允许其他应用访问或修改数据。其他应用程序使用ContentResolver根据Uri去访问操作指定数据。ContentProvider主要以表格的形势组织数据,有行列的层次性。另外还支持图片,视频等。
创建ContentProvider
- 自定义ContentProvider,该类继承ContentProvider,实现六个必须需要实现的抽象方法
public class MyContentProvider extents ContentProvider{
/*
* 创建时被调用
*/
@Override
public boolean onCreate(){
return false;
}
/*
* 根据Uri查询符合selection条件的全部记录,projection是一个列名列表,选择出指定的数据列,有点sql的select的意思
*/
@Override
public Cursor query(Uri uri,String[] project,String selection,String[] selectionArgs,String sortOrder){
//一般使用SQLiteDatabase进行数据的增删查改
return null;
}
/*
* 返回Uri查询出的selection条件的数据的MIME类型
*/
@Override
public String getType(Uri uri){
//当对应多条记录时 以vnd.android.cursor.dir/开头
//当对应单条记录时 以vnd.android.cursor.item/开头
return null;
}
/*
* 根据Uri插入对应的value的数据
*/
@Override
public Uri insert(Uri uri,ContentValues values){
return null;
}
/*
* 根据Uri删除selection匹配的记录
*/
@Override
public int delete(Uri uri,String selection,String[] selectionArgs){
return 0;
}
/*
* 根据Uri修改selection匹配的记录
*/
@Override
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
return 0;
}
}
- 在AndroidManifest中注册该ContentProvider
<provider
android:name=".MyContentProvider"
android:authorities="com.xxxx.xxx.MyContentProvider" //唯一标识,通过它外部应用访问MyContentProvider
android:exported="true" // 属性用于指示该服务是否能够被其他应用程序组件调用或跟它交互。如果设置为true,则能够被调用或交互,否则不能
android:multiprocess="true" //为true时:多实例 false:单实例
/>
还有一些其他属性
readPermission:使用Content Provider的查询功能所必需的权限,即使用ContentProvider里的query()函数的权限;
writePermission:使用ContentProvider的修改功能所必须的权限,即使用ContentProvider的insert()、update()、delete()函数的权限;
permission:客户端读、写 Content Provider 中的数据所必需的权限名称。readPermission和writePermission属性优先于本设置。 如果同时设置了readPermission属性,则其将控制对 Content Provider 的读取。 如果设置了writePermission属性,则其也将控制对 Content Provider 数据的修改。也就是说如果只设置permission权限,那么拥有这个权限的应用就可以实现对这里的ContentProvider进行读写;如果同时设置了permission和readPermission那么具有readPermission权限的应用才可以读,拥有permission权限的才能写!也就是说只拥有permission权限是不能读的,因为readPermission的优先级要高于permission;如果同时设置了readPermission、writePermission、permission那么permission就无效了。
android:permission="com.xxx.myPermission"
android:readPermission="com.xxx.myPermission.read"
android:writePermission="com.xxx.myPermission.write"
Uri组成
如: content://com.xxx.xxx.myContentProvider/hello 分为三部分
- content:// :类似网络协议的http://
- com.xxx.xxx.myContentProvider:是指在AndroidManifest中authorities属性,由该部分找到操作的ContentProvider
- hello:资源部分,访问不同的资源,动态改变
ContentResolver操作数据
首先ContentResolver到底是什么,由上面描述可知,ContentProvide的作用是用来暴露数据,而ContentResolver就是用来操作数据
由关系图可以看出,当应用A想要对B的数据进行增删查改时,就需要通过ContentResolver来实现。而ContentResolver通过Context提供的 getContentResolver方法获取。然后通过调用ContentResolver的CRUD方法操作数据
- query(Uri uri,String[] project,String selection,String[] selectionArgs,String sortOrder):当应用A调用该方法时,相当于调用了Uri指向的ContentProvider的query方法
- insert(Uri uri,ContentValues values)
- delete(Uri uri,String selection,String[] selectionArgs)
- public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs)
首先来举例 查询 实例:
参数 | 类型 | 对应SQL部分 | 描述 |
---|---|---|---|
uri | Uri | from table_name | 查询某个应用程序指定表 |
projection | String[] | select column1,column2 | 指定查询列名 |
selection | String | where column = value | where中约束条件 |
selectionArgs | String[] | 为where中的占位符提供具体的值 | |
orderBy | String | order by columns1,column2 | 指定排序方式 |
//将内容字符串解析成Uri对象
Uri uri = Uri.parse("content://com.xxx.xxx.myContentProvider/hello");
Cursor cursor = getContentResolver().query(uri,project,selection,selectionArgs,sortOrder);
if(cursor!=null){
while(cursor.moveToNext()){
String colum1 =cursor.getString(cursor.getColumnIndex("column1"));
int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
}
cursor.close();
}
添加
ContentValues values = new ContentValues();
values.put("column1","text");
values.put("column2",1);
getContentResolver().insert(uri,values);
修改
ContentValues values = new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1=? and column2 = ?",new String[]{"text","1"});
//使用selection和selectionArgs对想要更新的数据进行约束
删除
getContentResolver().delete(uri,values,"column2=?",new String[]{"1"});
//使用selection和selectionArgs对想要更新的数据进行约束
读取系统ContentProvider
下面展示在实际开发中如何读取系统的联系人。
private void readContacts(){
Cursor cursor = null;
try{
//查询联系人数据
cursor = getContentResolver().query(
ContactsContract.commonDataKinds.Phone.CONTENT_URI,
null,null,null,null);
while(cursor.moveToNext()){
//获取联系人姓名
String Name=cursor.getString(
cursor.getColumnIndex(ContactContract.CommonDataKinds.Phone.DISPLAY_NAME));
//存储姓名操作
//获取联系人手机号码
String number = cursor.getString(
cursor.getColumnIndex(ContactContract.CommonDataKinds.Phone.NUMBER));
//存储手机号码操作
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(cursor!=null){
cursor.close();
}
}
}
监听ContentProvider数据变化
- 操作者
在操作ContentResolver时,通过调用
getContext().getContentResolver().notifyChange(uri,null);
会通知注册在该Uri的监听者,该ContentProvider上的数据发生了变化
- 观察者
要监听指定Uri的ContentProvider的数据变化,需要利用ContentObserver。注册代码如下
/**
* Uri 指定uri
* notifyForDescendents :boolean类型,true时,子路径的数据改变也会通知,false:当前路径才通知
* MyObserver 继承ContentObserver,当所监听数据变化,调用onChange()
*/
getContentResolver().registerContentObserver(uri,true,new MyObserver(new Handler()));
//自定义匿名内部监听类
private final class MyObserver extends ContentObserver{
public MyObserver(Handler handler){
super(handler);
}
public void onChange(boolean selfChange){
//当数据改变时执行相应操作
}
}
资料
[1] ContentProvider权限设置
[2] 疯狂Android讲义
[3] 第一行代码