组件之ContentProvider全面解析

ContentProvider是在应用程序间共享数据的一种接口机制,它还可以选择只对哪一部分数据进行共享,从而保证程序中的隐私数据不会有泄漏风险,ContentProvider主要负责存储和共享数据。其他应用程序通过ContentResolver类从该内容提供者中获取或存入数据。

一、访问系统提供的Provider数据

(1)ContentResolve类

  • ContentResolver类中提供的一系列用于对数据进行增删改查操作的方法也酷似SQLiteDatabase的那些辅助性方法:
    insert()方法用于添加数据(Uri对象,ContentValues对象)
    update()方法用于更新数据(Uri对象,ContentValues对象,修改的约束条件,占位符的值)
    delete()方法用于删除数据(Uri对象,删除的约束条件,占位符的值)
    query()方法用于查询数据(Uri对象,查询的列名,查询的约束条件,占位符的值,排序方式)
  • 通过Context 中的getContentResolver()方法实例化一个ContentResolve对象
  • 调用该对象的增删改查方法去操作ContentProvider中的数据。

(2)读取联系人信息

  • 读取联系人信息
    private void Contacts() {
        //获取联系人的数据
        Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
                null, null, null, null);
        if (cursor != null) {
            while (cursor.moveToFirst()) {
                //获取联系人姓名
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                //获取联系人ID
                int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
                //获取联系人手机号数据
                Cursor cursorPhone = getContentResolver().query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER},
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id,
                        null, null);
                if (cursorPhone != null) {
                    while (cursorPhone.moveToFirst()) {
                        //获取联系人手机号
                        String phone = cursorPhone.getString(cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    }
                    cursorPhone.close();
                }
            }
            cursor.close();
        }
    }
  • 在配置文件中声明权限

  • 注意:Android6.0以上的系统要求部分权限还要手动申请
int hasWriteContactsPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 100);
        }
        return;
}
  • 权限回调方法
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100){
            for (int i = 0; i < grantResults.length; i ++){
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED){
                    //未获取权限
                }
            }
        }
    }

二、自定义创建Provider数据

(1)工具类:UriMatcher

  • addURI()方法用来传入URI,它接收三个参数(权限,路径,匹配码)
  • match()方法用来匹配URI,接受一个Uri对象,返回值是某个能够匹配这个Uri对象所对应的匹配码,利用这个匹配码,就可以判断出调用方期望访问的是哪张表中的数据。

(2)自定义ContentProvider

  • 新建一个类去继承ContentProvider,重写ContentProvider的抽象方法。
public class MyContentProvider extends ContentProvider {
    /**
     * 创建ContentProvider后调用
     *
     * @return
     */
    @Override
    public boolean onCreate() {
        return false;
    }

    /**
     * 用于供外部应用从ContentProvider中查询数据
     *
     * @param uri
     * @param projection
     * @param selection
     * @param selectionArgs
     * @param sortOrder
     * @return
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return null;
    }

    /**
     * 返回当前Uri所代表数据的MIME类型
     *
     * @param uri
     * @return
     */
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    /**
     * 用于供外部应用向ContentProvider中增加数据
     *
     * @param uri
     * @param values
     * @return
     */
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }

    /**
     * 用于供外部应用从ContentProvider中删除数据
     *
     * @param uri
     * @param selection
     * @param selectionArgs
     * @return
     */
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    /**
     * 用于供外部应用更新ContentProvider中数据
     *
     * @param uri
     * @param values
     * @param selection
     * @param selectionArgs
     * @return
     */
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
}
  • 在配置文件中进行注册,并注明属性
        
        
        

(3)示例具体实现

public class DBOpenHelper extends SQLiteOpenHelper {

    public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建表student
        db.execSQL("create table if not exists animal(" +
                "_id integer primary key autoincrement, " +
                "name text not null , " +
                "age integer not null , " +
                "sex text not null)");
        db.execSQL("create table if not exists person(" +
                "_id integer primary key autoincrement, " +
                "name text not null , " +
                "age integer not null , " +
                "sex text not null)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion) {
            case 1:
                db.execSQL("create table if not exists person(" +
                        "_id integer primary key autoincrement, " +
                        "name text not null , " +
                        "age integer not null , " +
                        "sex text not null)");
                break;
        }
    }
}
public class MyContentProvider extends ContentProvider {
    public DBOpenHelper dbOpenHelper;
    public static UriMatcher uriMatcher;
    public static final int ANIMAL_DIR = 1001;
    public static final int ANIMAL_ITEM = 1002;
    public static final int PERSON_DIR = 1003;
    public static final int PERSON_ITEM = 1004;
    public static final String AUTHORITIES = "com.example.dbsqlite.mycontentprovider";

    //对UriMatcher进行了初始化
    //id用以区分表中不同的数据记录,如果没有id就返回全部。用到了转义符。#代表任意数字,*代表任意字母。
    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITIES, "animal", ANIMAL_DIR);
        uriMatcher.addURI(AUTHORITIES, "animal/#", ANIMAL_ITEM);
        uriMatcher.addURI(AUTHORITIES, "person", PERSON_DIR);
        uriMatcher.addURI(AUTHORITIES, "person/#", PERSON_ITEM);
    }

    /**
     * 该方法在ContentProvider被其它应用第一次访问它时才会被创建
     * 返回true表示内容提供器初始化成功
     *
     * @return
     */
    @Override
    public boolean onCreate() {
        dbOpenHelper = new DBOpenHelper(getContext(), "UserInfo.db", null, 2);
        return true;
    }

    /**
     * 用于供外部应用从ContentProvider中查询数据
     *
     * @param uri
     * @param projection
     * @param selection
     * @param selectionArgs
     * @param sortOrder
     * @return
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        String id;
        Cursor cursor = null;
        //获取到SQLiteDatabase的实例
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        //判断用户查询哪张表
        switch (uriMatcher.match(uri)) {
            case ANIMAL_DIR:
                cursor = db.query("animal", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case ANIMAL_ITEM:
                //调用Uri对象的getPathSegments()方法
                //它会将内容URI权限之后的部分以“/”符号进行分割,并把分割后的结果放入到一个字符串列表中,
                //那这个列表的第0个位置存放的就是路径,第1个位置存放的就是id
                id = uri.getPathSegments().get(1);
                cursor = db.query("animal", projection, "id=?", new String[]{id}, null, null, sortOrder);
                break;
            case PERSON_DIR:
                cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case PERSON_ITEM:
                id = uri.getPathSegments().get(1);
                cursor = db.query("person", projection, "id=?", new String[]{id}, null, null, sortOrder);
                break;
        }
        return cursor;
    }

    /**
     * 返回当前Uri所代表数据的MIME类型
     * 内容URI所对应的MIME字符串主要由三部分组分,
     * Android对这三个部分做了以下格式规定:必须以vnd开头;
     * 如果内容URI以路径结尾,则后接android.cursor.dir/,
     * 如果内容URI以id结尾,则后接android.cursor.item/;
     * 最后接上vnd.< authority>.< path>。
     *
     * @param uri
     * @return
     */
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        //与已经注册的Uri进行匹配
        switch (uriMatcher.match(uri)) {
            case ANIMAL_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.dbsqlite.mycontentprovider.animal";
            case ANIMAL_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.dbsqlite.mycontentprovider.animal";
            case PERSON_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.dbsqlite.mycontentprovider.person";
            case PERSON_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.dbsqlite.mycontentprovider.person";
        }
        return null;
    }

    /**
     * 用于供外部应用向ContentProvider中增加数据
     *
     * @param uri
     * @param values
     * @return
     */
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        Uri uri_return = null;
        long id;
        //判断向哪张表里添加数据
        switch (uriMatcher.match(uri)) {
            case ANIMAL_DIR:
            case ANIMAL_ITEM:
                id = db.insert("animal", null, values);
                uri_return = Uri.parse("content://" + AUTHORITIES + "/animal/" + id);
                break;
            case PERSON_DIR:
            case PERSON_ITEM:
                id = db.insert("person", null, values);
                uri_return = Uri.parse("content://" + AUTHORITIES + "/person/" + id);
                break;
        }
        return uri_return;
    }

    /**
     * 用于供外部应用从ContentProvider中删除数据
     *
     * @param uri
     * @param selection
     * @param selectionArgs
     * @return
     */
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        String id;
        int row = 0;
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        switch (uriMatcher.match(uri)) {
            case ANIMAL_DIR:
                row = db.delete("animal", selection, selectionArgs);
                break;
            case ANIMAL_ITEM:
                id = uri.getPathSegments().get(1);
                row = db.delete("animal", "id=?", new String[]{id});
                break;
            case PERSON_DIR:
                row = db.delete("person", selection, selectionArgs);
                break;
            case PERSON_ITEM:
                id = uri.getPathSegments().get(1);
                row = db.delete("person", "id=?", new String[]{id});
                break;
        }
        return row;
    }

    /**
     * 用于供外部应用更新ContentProvider中数据
     *
     * @param uri
     * @param values
     * @param selection
     * @param selectionArgs
     * @return
     */
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        String id;
        int row = 0;
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        switch (uriMatcher.match(uri)) {
            case ANIMAL_DIR:
                row = db.update("animal", values, selection, selectionArgs);
                break;
            case ANIMAL_ITEM:
                id = uri.getPathSegments().get(1);
                row = db.update("animal", values, "id=?", new String[]{id});
                break;
            case PERSON_DIR:
                row = db.update("person", values, selection, selectionArgs);
                break;
            case PERSON_ITEM:
                id = uri.getPathSegments().get(1);
                row = db.update("person", values, "id=?", new String[]{id});
                break;
        }
        return row;
    }
}

三、使用ContentResolver调用ContentProvider操作数据库数据

(1)ContentResolver基础方法

    ContentResolver resolver = getContentResolver();
    //该方法用于往ContentProvider添加数据。 
    public Uri insert(Uri uri, ContentValues values);
    //该方法用于从ContentProvider删除数据。 
    public int delete(Uri uri, String selection, String[] selectionArgs);
    //该方法用于从ContentProvider中获取数据。 
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
    //该方法用于更新ContentProvider中的数据。
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);

(2)数据的增删改查操作

    private ContentValues values;
    private ContentResolver resolver;
    private Uri uri;
    private Uri uri_new;
    private Uri uri_return;

    public void init() {
        values = new ContentValues();
        resolver = getContentResolver();
        uri = Uri.parse("com.example.dbsqlite.mycontentprovider/animal");
    }

    public void insert() {
        values.put("name", "cat");
        values.put("age", 2);
        values.put("sex", "male");
        uri_return = resolver.insert(uri, values);
        values.clear();
        values.put("name", "tiger");
        values.put("age", 2);
        values.put("sex", "male");
        uri_return = resolver.insert(uri, values);
        String id = uri_return.getPathSegments().get(1);
        uri_new = Uri.parse("content://com.example.dbsqlite.mycontentprovider/animal" + id);
        values.clear();
        values.put("name", "lion");
        values.put("age", 4);
        values.put("sex", "female");
        uri_return = resolver.insert(uri, values);
        values.clear();
    }

    public void delete() {
        resolver.delete(uri_new, null, null);
    }

    public void update() {
        values.put("age", 5);
        resolver.update(uri, values, "age=?", new String[]{"4"});
    }

    public void query() {
        Cursor cursor = resolver.query(uri, null, null, null, null);
        if (cursor != null) {
            while (cursor.moveToFirst()) {
                String name = cursor.getString(cursor.getColumnIndex("name"));
            }
            cursor.close();
        }
    }

你可能感兴趣的:(组件之ContentProvider全面解析)