ContentProvider
sky-mxc 总结 转载注明:https://sky-mxc.github.io
内容提供者,应用程序间的数据交互,是为存储和获取数据提供的统一接口。
Contentprovider为应用间数据交互提供了安全的环境,它允许把自己的应用数据开放给其他应用进行 CRUD。怎么样进行操作可以自己规定,不用担心权限的问题。当然如果不想被被人读取自己应用的数据就不需要这个内容提供者。
ContentResolver来访问和操作我们的数据。
ContentResolver 通过我们注册的uri就可以知道我们开放的数据。
关于uri 参考这篇文章:http://blog.csdn.net/dlutbrucezhang/article/details/8917303
创建一个ContentProvider
创建自己的内容提供程序 只需继承ContentProvider即可。
这里就以insert 和 query 为例
package com.skymxc.demo.contentprovider.util;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils;
/**
* Created by sky-mxc
*/
public class StudentProvider extends ContentProvider {
private DBHelper dbHelper;
private UriMatcher uriMatcher;
//匹配结果是一张表
private static final int STUDENTS = 1;
//匹配结果是一个条数据
private static final int STUDENT = 2;
//一般是包名 避免重复
private static final String AUTHORITY = "com.skymxc.demo";
@Override
public boolean onCreate() {
dbHelper = new DBHelper(getContext());
//初始化 uri匹配者 UriMatcher.NO_MATCH:匹配不上时返回
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//添加能够匹配的uri格式 参数1authorities 匹配住机。 参数2 匹配路径 参数3 code : match success return this code;
// 代表这个uri 操作的是一个表,匹配码是 STUDENTS
uriMatcher.addURI(AUTHORITY,"student", STUDENTS);
//代表这个uri 操作的是一条数据 匹配成功后返回 STUDENT
uriMatcher.addURI(AUTHORITY,"student/#",STUDENT);
return true;
}
/**
* 查询操作
* @param uri
* @param projection 要查询的列
* @param condition 查询条件
* @param values 查询参数
* @param sortOrder 排序
* @return
*/
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String condition, String[] values, String sortOrder) {
Cursor cursor =null;
SQLiteDatabase db= dbHelper.getDB();
//匹配这个uri 要查询一张表还是 某条数据
switch (uriMatcher.match(uri)){
case STUDENT:
//查询某条数据 ContentUris :工具类 可以解析出id
long id= ContentUris.parseId(uri);
String where ="_id ="+id+" ";
if (!TextUtils.isEmpty(condition)){
where+= " and "+condition;
}
cursor= db.query(DBHelper.TABLE_NAME,projection,where,values,null,null,sortOrder);
break;
case STUDENTS:
//查询一张表
cursor = db.query(DBHelper.TABLE_NAME,projection,condition,values,null,null,sortOrder);
break;
default:
throw new IllegalArgumentException("match fail 。uri:"+uri+"");
}
return cursor;
}
@Nullable
@Override
public String getType(Uri uri) {
String type="unKnow";
switch (uriMatcher.match(uri)){
case STUDENT:
type="vnd.android.cursor.item/student";
break;
case STUDENTS:
type= "vnd.android.cursor.dir/student";
break;
}
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbHelper.getDB();
switch (uriMatcher.match(uri)){
case STUDENT:
break;
case STUDENTS:
db.insert(DBHelper.TABLE_NAME,"_id",values);
break;
}
return uri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
创建完之后还需要在manifest文件中注册 才能被其他应用看到,通过 元素注册一个内容提供者
<!--
android:exported 设置此provider是否可以被其他应用使用。
android:readPermission 该provider的读权限的标识
android:writePermission 该provider的写权限标识
android:permission provider读写权限标识
android:grantUriPermissions 临时权限标识
-->
<provider
android:authorities="com.skymxc.demo"
android:name=".util.StudentProvider"
android:exported="true"/>
关于临时权限标识 grantUriPermissions :true时,意味着该provider下所有数据均可被临时使用;false时,则反之,但可以通过设置标签来指定哪些路径可以被临时使用。这么说可能还是不容易理解,我们举个例子,比如你开发了一个邮箱应用,其中含有附件需要第三方应用打开,但第三方应用又没有向你申请该附件的读权限,但如果你设置了此标签,则可以在start第三方应用时,传入FLAG_GRANT_READ_URI_PERMISSION或FLAG_GRANT_WRITE_URI_PERMISSION来让第三方应用临时具有读写该数据的权限。
> 到这里 一个简单的内容提供者就创建完成了
ContentResolver
可以看做是客户端 与ContentProvider 对应 ,ContentProvider 负责提供数据操作接口 ,ContentResolver 可以调用ContentProvider的数据接口对数据进行操作
为了测试上面定义的ContentProvider ,另创建一个Module 进行读取
private void read() {
ContentResolver resolver= getContentResolver() ;
String uriStr ="content://com.skymxc.demo/student";
Cursor cursor= resolver.query(Uri.parse(uriStr),new String[]{"_id","name","age"},null,null,"age");
StringBuffer sb = new StringBuffer("============student==================\n");
while (cursor !=null &&cursor.moveToNext()){
long id = cursor.getLong(cursor.getColumnIndex("_id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
sb.append("==="+id+"===\n");
sb.append("name:"+name+"\n");
sb.append("age:"+age+"\n");
}
sb.append("============================");
tv.setText(sb.toString());
if (cursor != null){
cursor.close();
}
}
insert
private void insert() {
String name = etName.getText().toString();
String age = etAge .getText().toString();
ContentResolver resolver = getContentResolver();
String uriStr="content://com.skymxc.demo/student";
ContentValues cv = new ContentValues();
cv.put("name",name);
cv.put("age",age);
resolver.insert(Uri.parse(uriStr),cv);
}
ContentResolver 还可以用来操作 短信,联系人,多媒体等 数据,这里写个读取短信的实例
读取短信的权限
“`xml
““
/**
* 短信查询
*/
private void querySms() {
String[] projection = new String[]{"_id","address","person","body","type"};
StringBuffer sb = new StringBuffer("短信数据=============\n");
ContentResolver resolver= getContentResolver();
Cursor cursor = resolver.query(Uri.parse("content://sms/"),projection,null,null,null);
while (cursor != null && cursor.moveToNext()){
sb.append("id:"+cursor.getInt(cursor.getColumnIndex("_id")));
sb.append("\naddress:"+cursor.getString(cursor.getColumnIndex("address")));
sb.append("\nperson:"+cursor.getString(cursor.getColumnIndex("person")));
sb.append("\nbody:"+cursor.getString(cursor.getColumnIndex("body")));
sb.append("\ntype:"+cursor.getString(cursor.getColumnIndex("type")));
sb.append("\n=================================================");
}
tv.setText(sb.toString());
}
ContentObserver
内容观察者,可以给某些数据注册观察者,当数据改变时做出有些操作
初始化观察者
private ContentObserver observer = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.e("MainActivity","======数据改变了===");
}
};
````
> 注册观察者
<div class="se-preview-section-delimiter"></div>
```java
Uri uri = Uri.parse("content://"+StudentProvider.AUTHORITY+"/student");
//为student 注册观察者
/**
* parameter1 观察的uri
* parameter2 uri的后代是否连带 观察
* parameter3 observer
*/
getContentResolver().registerContentObserver(uri,true,observer);
内容改变时 通知观察者
系统会首先查找 uri 扫描(手机上)所有的注册的observer 的uri 匹配之后执行 observer的onChange 方法
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbHelper.getDB();
int line=0;
switch (uriMatcher.match(uri)){
case STUDENT:
break;
case STUDENTS:
line= (int) db.insert(DBHelper.TABLE_NAME,"_id",values);
break;
}
if (line>0){
getContext().getContentResolver().notifyChange(uri,null);
}
return uri;
}
当在另一个应用插入数据时 change()调用
E/MainActivity: ======数据改变了===