安卓 ContentProvider(内容提供器) 基础

安卓的内容提供器是四大组件之一,提供了一种跨应用程序访问数据的方式,这包含两方面:(1)在自己的应用程序中访问其他应用程序的数据库(例如通过系统提供的内容提供器访问联系人、短信、图片等)。(2)构建自己的ContentProvider开放自己的数据库给其他的应用程序(或者自己应用程序的访问)。
和内容提供器相关有三个重要的类ContentResolver,ContentProvider与ContentObserver。

1. ContentResolver

ContentResolver可以通过Context的getContentResolver()方法取得实例,每个应用程序在创建时都会提供一个ContentResolver,ContentResolver相当于一个代理,通过ContentResolver来对内容提供器进行操作,他提供了CURD方法,对应着数据库中的CURD操作。
ContentResolver通过Uri来匹配具体的访问数据表。内容提供器中的Uri由三部分组成,
第一部分是内容提供器的标识content://,第二部分是authority,用来区分要访问数据库所属的应用程序,第三部分是path,标识着要访问的数据表或具体的那条数据。因此一个标准的Uri写法如下

content://com.example.app.provider/tablename
   一                          二                             三

*符号表示匹配任意长度的任意字符

符号表示匹配任意长度的数字

content://com.example.app.provider/*
表示访问该应用程序内的任意一张表
content://com.example.app.provider/tablname/#
表示访问tablename表中的任意一行

ContentResolver提供query()、insert()、update()、delete()用来查询、增加、更新、删除数据。
query()方法查询数据:

Cursor cursor=getContentResolver().query(uri,projection,selection,selectionArgs,sortOrder);

uri指明查询的路径,projection指定要查询的列,selection与 selectionArgs指定查询的条件(如Sql中 “where id > 10”),sortOrder指定查询结果排序方式。

insert()方法插入数据:

ContentValues values=new ContentValues();
value.put("name","jack");
value.put("age",10);
getContentResolver.insert(uri,values);

update()方法更新数据:

ContentValues values=new ContentValues();
values.put("name","macro");
getContentResovler().update(uri,values,"name= ? and age=? " , new String[] {" jack","10"});

delete()方法删除数据:

getContentResolver.delete(uri,"name = ?" , new String[] {"macro"});

2. 创建内容提供器ContentProvider

自定义内容提供器需要重写6个抽象方法:onCreate(),getType(),query(),insert(),update(),delete(),
一个基本的自定义内容提供器框架如下

public class MyProvider extends ContentProvider {

    public static final int TABLE_DIR=0;
    public static final int TABLE_ITEM=1;

    private static UriMatcher uriMatcher;

    static
    {
        uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI("com.example.app.provider","tablename",TABLE_DIR);
        uriMatcher.addURI("com.example.app.provider","tablename/#",TABLE_ITEM);
    }

    @Override
    public boolean onCreate() {

    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri))
        {
            case TABLE_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.app.provider.tablename";
                break;
            case TABLE_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.app.provider.tablename";
                break;
            default:
                break;
        }
    }


    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        //这里填写查询逻辑
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        //这里填写插入逻辑
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        //这里填写更新逻辑
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        //这里填写删除逻辑
    }
}

TABLE_DIR ,TABLE_ITEM为定义的两个常量,分别表示整个表和表中Item。
UriMatcher是一个uri匹配器,可以自己设置authority , path 与code( int 类型) 的对应关系,例如uriMatcher.addURI("com.example.app.provider","tablename",TABLE_DIR)就建立了 authority=com.example.app.provider ,path=tablename 与TABLE_DIR 之间的关系,通过uriMather.match("content://com.example.app.provider/tablename")就会返回TABLE_DIR。

当ContentResolver尝试访问数据时候,内容提供器就会被初始化,onCreate()方法执行,返回值代码是否初始化成功。这里往往添加一些数据库的创建升级等操作(例如获取DatabaseHelper实例 dbHelper=new MyDatabaseHelper(。。。) )。
query()、insert()、update()、delete()中用来处理根据提供的uri与其他参数来操作数据库的实际逻辑,例如查询数据库、插入数据等。

getType()方法会根据Uri返回对应MIME类型。MIME字符串也由三部分组成:
1.必须以vnd开头
2.如果URI以表名结尾,vnd后面接android.cursor.dir,以表中某一id(item)结果,vnd后面接android.cursor.item。
3.然后在最后接上vnd.<authority>.<path>。

例如

vnd.android.cursor.dir/vnd.com.example.app.provider.table
表示访问表
vnd.android.cursor.item/vnd.com.example.app.provider.table
表示访问表中某一item

内容提供器是四大组件之一,因此需要在AndroidManifest.xml文件中配置一下。

<provider
        android:name=".MyProvider"
        android:authorities="com.example.app.provider"
        android:enable="true"
        android:exported="true"
    >
</provider>

enable表示是否启用这个内容提供器,exported表示是否允许其他应用程序访问这个内容提供器。

3. ContentObserver内容监听者

某些时候数据库发生改变(例如新建了联系人,从网络刷新了新数据、或者来短信了),我们不能及时知道就导致已有的数据成为旧数据,然而通过query()方法再去查询需要主要去操作或者另起线程定期查询这样效率低而且很被动,这时候就可以使用ContentObserver,ContentObserver使用观察者模式,当数据库改变时候通知注册的observer实例对象执行更新操作。
创建自己的内容观察者对象:

 private ContentObserver mContentObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange, Uri uri) {
                //这里执行更新逻辑;
            }
        }
    };

继承ContentObserver类需要重写onChange()方法,当数据库发生改变时候会回调这个onChange()方法。声明ContentObserver实例对象时候需要传入一个Handler()对象。

通过ContentResolver来注册和取消注册这个观察者

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

推荐阅读更多精彩内容