组件之ContentProvider全面解析

一、ContentProvider使用

(1)ContentProvider方法

  • onCreate:创建ContentProvider后调用
  • getType:返回当前Uri所代表数据的MIME类型
  • query:用于供外部应用从ContentProvider中查询数据
  • insert:用于供外部应用向ContentProvider中增加数据
  • delete:用于供外部应用从ContentProvider中删除数据
  • update:用于供外部应用更新ContentProvider中数据
    (2)SQLiteOpenHelper类的实现
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;
        }
    }
}

(3)ContentProvider 类的实现

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;
    }
}

(5)在配置文件中进行注册,并注明属性

        <!--authorities设置Provider的权限-->
        <!--exported指明该Provider可被其它程序访问-->
        <provider
            android:name=".MyContentProvider"
            android:authorities="ccom.example.dbsqlite.mycontentprovider"
            android:exported="true"
            android:readPermission="com.example.provider.myprovider" />

(6)ContentResolver方法

  • insert:用于往ContentProvider添加数据。
  • delete:用于从ContentProvider删除数据。
  • query:用于从ContentProvider中获取数据。
  • update:用于更新ContentProvider中的数据。

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

    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源码解析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容