Android 四大组件之一 ContentProvider

简介

上一篇博客已经介绍了Android原生数据库的使用,本篇博客就来记录Android的四大组件之一的内容提供者(ContentProvider),ContentProvider主要用于不同应用之间实现数据共享的功能,Android系统也提供对应的接口供应用程序读取数据,比如多媒体、联系人、短信等,它的数据源不单单是数据库,还有可能是XML、文件、网络等;

数据共享

使用

在AndroidManifest注册

在Android文件AndroidManifest.xml注册
authorities:访问表的主机地址;
exported:是否允许对外应用程序访问,true允许,false不允许,默认false;

 <!--给内容提供者提供定义一个uri,一般建议使用包名+类名,以供其它程序调用 -->
<provider
    android:name="com.dream.contentprovider.provider.PersonProvider"
    android:authorities="com.dream.contentprovider"
    android:exported="true"/>
继承ContentProvider

Android系统为我们提供ContentProvider类,我们继承这个类实现onCreate()、getType()、insert()、delete()、update()、query();
onCreate():内容提供者初始化的时候调用,一般这里执行数据库创建、升级操作。
getType():根据给定的Uri返回一个MIME类型的数据。
insert():Uri表示需要操作哪张表,ContentValues需要插入的值,插入成功返回一个Uri;
delete():Uri表示需要操作哪张表,selection和selectionArgs表示筛选的条件,返回受影响的行。
update():Uri表示需要操作哪张表,ContentValues需要插入的值,selection和selectionArgs表示筛选的条件,返回受影响的行。
query():Uri表示需要操作哪张表,projection需要查询表中那些字段,selection和selectionArgs表示筛选的条件,sortOrder对查询查询结果进行排序,将查询结果放到Cursor返回。

public class PersonProvider extends ContentProvider {
    private static String TAG = PersonProvider.class.getSimpleName();

    //这里的AUTHORITY就是我们在AndroidManifest.xml中配置的authorities
    public static final String AUTHORITY = "com.dream.contentprovider";

    //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码,也就是说如果找不到匹配的类型,返回-1
    private static final UriMatcher URI_MATCHER;

    //匹配不同的表的code
    private static final int ALL_PERSON = 1;
    private static final int PERSON = 2;

    //数据库的名字
    public static final String DB_NAME = "test.db";
    //数据库版本
    public static final int DB_VERSION = 1;
    //数据库表的名称
    private static final String TABLE_NAME = "person";

    private MyDBHelper dbHelper;
    private SQLiteDatabase db;

    static {
        //创建一个路径识别器
        URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
        //1.指定一个路径的匹配规则
        //如果路径满足content://com.dream.contentprovider.provider.PersonProvider/person,返回值就是(ALL_PERSON)=1
        URI_MATCHER.addURI(AUTHORITY, "/person", ALL_PERSON);
        //2.#号为通配符
        //如果路径满足content://com.dream.contentprovider.provider.PersonProvider/person/3,返回值就是(PERSON)=2
        URI_MATCHER.addURI(AUTHORITY, "/person/#", PERSON);
    }


    /**
     * 一般是对象第一次被创建时调用的方法
     *
     * @return
     */
    @Override
    public boolean onCreate() {
        dbHelper = new MyDBHelper(this.getContext(), DB_NAME, null, DB_VERSION);
        db = dbHelper.getReadableDatabase();
        return true;
    }


    /**
     * 让别人去调用返回结果
     *
     * @param uri           匹配条件
     * @param projection    选择的列
     * @param selection     查询条件
     * @param selectionArgs 查询条件的value
     * @param sortOrder     排序
     * @return
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        int type = URI_MATCHER.match(uri);
        switch (type) {
            case ALL_PERSON:
                return db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
            case PERSON:
                //获取具体某一行的数据
                String id = uri.getPathSegments().get(1);
                return db.query(TABLE_NAME, projection, "_id = ?", new String[]{id}, null, null, sortOrder);
            default:
                break;
        }
        return null;
    }

    //如果是单条记录应该返回以vnd.android.cursor.item/ 为首的字符串
    //如果是多条记录,应该返回vnd.android.cursor.dir/ 为首的字符串
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        int type = URI_MATCHER.match(uri);
        switch (type) {
            case ALL_PERSON:
                return "vnd.android.cursor.dir/vnd.com.dream.contentprovider.provider.person";
            case PERSON:
                return "vnd.android.cursor.item/vnd.com.dream.contentprovider.provider.person";
            default:
                return null;
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        int type = URI_MATCHER.match(uri);
        switch (type) {
            case ALL_PERSON:
                long row = db.insert(TABLE_NAME, null, values);
                return ContentUris.withAppendedId(uri, row);
            case PERSON:
                long row2 = db.insert(TABLE_NAME, null, values);
                return ContentUris.withAppendedId(uri, row2);
            default:
                return null;
        }
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        int type = URI_MATCHER.match(uri);
        int updateRow = 0;
        switch (type) {
            case ALL_PERSON:
                updateRow = db.delete(TABLE_NAME, selection, selectionArgs);
                break;
            case PERSON:
                //获取具体某一行的数据
                String id = uri.getPathSegments().get(1);
                updateRow = db.delete(TABLE_NAME, "_id = ?", new String[]{id});
                break;
            default:
                break;
        }
        return updateRow;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        int type = URI_MATCHER.match(uri);
        int updateRow = 0;
        switch (type) {
            case ALL_PERSON:
                updateRow = db.update(TABLE_NAME, values, selection, selectionArgs);
                break;
            case PERSON:
                //获取具体某一行的数据
                String id = uri.getPathSegments().get(1);
                updateRow = db.update(TABLE_NAME, values, "_id = ?", new String[]{id});
                break;
            default:
                break;
        }
        return updateRow;
    }
}

当APP启动的时候,onCreate()方法被执行,此时已经创建了数据库。

跨进程调用

private static final Uri STUDENT_ALL_URI = Uri.parse("content://" + PersonProvider.AUTHORITY + "/person");拼接完整的地址为:"content://com.dream.contentprovider/person""content://com.dream.contentprovider/person/id",其中这个id表示表中数据的行数,id=0、1、 2 ...。当和UriMatcher 进行匹配返回匹配类型。不管是进程内还是跨进程之间通信关键是否URL正确,否则会出现如下错误:

URL有误
private static final Uri STUDENT_ALL_URI = Uri.parse("content://com.dream.contentprovider/person");
插入数据insert()
 mUserProvider = getContentResolver();
 ContentValues values = new ContentValues();
 values.put("name", "张三");
 values.put("age", "18");
 values.put("sex", "男");
 mUserProvider.insert(STUDENT_ALL_URI, values);
插入数据
插入数据delete()
 mUserProvider = getContentResolver();
 mUserProvider.delete(STUDENT_ALL_URI, "name = ?", new String[]{"张三"});
删除数据
更新数据update()
 mUserProvider = getContentResolver();
 ContentValues values = new ContentValues();
 values.put("age", "19");
 values.put("sex", "女");
 mUserProvider.update(STUDENT_ALL_URI, values, "name = ?", new String[]{"张三"});
更新数据
查询数据query()

记得关闭游标,防止内存泄漏

 mUserProvider = getContentResolver();
 String result = "";
 Cursor cursor = mUserProvider.query(STUDENT_ALL_URI, null, null, null);
 if (cursor != null) {
     try {
          while (cursor.moveToNext()) {
              String id = cursor.getString(cursor.getColumnIndex("_id"));
              String name = cursor.getString(cursor.getColumnIndex("NAME"));
              String age = cursor.getString(cursor.getColumnIndex("AGE"));
              String sex = cursor.getString(cursor.getColumnIndex("SEX"));
              result = result + "\n" + "_id=" + id + " name=" + name + " sex=" + sex + "  age=" + age;
          }
     } finally {
         cursor.close();
         cursor = null;
         mTextView.setText(result);
     }
 }
查询数据
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容