ContentProvider

2018-05-22 11:49:09 浏览数 (1)

ContentProvider

内容提供者,应用程序间的数据交互,是为存储和获取数据提供的统一接口。 Contentprovider为应用间数据交互提供了安全的环境,它允许把自己的应用数据开放给其他应用进行 CRUD。怎么样进行操作可以自己规定,不用担心权限的问题。

当然如果不想被被人读取自己应用的数据就不需要这个内容提供者。 ContentResolver来访问和操作我们的数据。 ContentResolver 通过我们注册的uri就可以找到我们开放的数据。

关于uri 参考这篇文章:http://blog.csdn.net/dlutbrucezhang/article/details/8917303

创建一个ContentProvider

创建自己的内容提供程序 只需继承ContentProvider即可。 这里就以insert 和 query 为例

代码语言:javascript复制

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文件中注册 才能被其他应用看到,通过 元素注册一个内容提供者

代码语言:javascript复制
<!--
    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 进行读取

代码语言:javascript复制
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

代码语言:javascript复制

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 还可以用来操作 短信,联系人,多媒体等 数据,这里写个读取短信的实例

读取短信的权限

代码语言:javascript复制
><uses-permission android:name="android.permission.READ_SMS"/>
>`
代码语言:javascript复制
/**
 * 短信查询
 */
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

内容观察者,可以给某些数据注册观察者,当数据改变时做出有些操作

初始化观察者

代码语言:javascript复制
private ContentObserver  observer = new ContentObserver(new Handler()) {
   @Override
   public void onChange(boolean selfChange) {
       super.onChange(selfChange);
       Log.e("MainActivity","======数据改变了===");
   }
};
`

注册观察者

代码语言:javascript复制

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 方法

代码语言:javascript复制
@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()调用

代码语言:javascript复制
E/MainActivity: ======数据改变了===

0 人点赞