<第一行代码>chapter7 ContentProvider

内容提供器

思维导图

最近在练习使用思维导图,献一下丑。。。

chapter7

什么是内容提供器

内容提供器主要用于在不同应用程序间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序里的数据,同时还能保证被访问数据的安全性。内容提供器可以选择要分享的数据,保证应用程序的隐私数据。一般有两种内容提供器的用法:

  1. 一个是使用现有的内容提供器来读取和操作相应程序中的数据。
  2. 创建自己的内容提供器给自己的应用程序数据提供外部访问接口。

访问其他程序中的数据

ContentResolver的基本用法

获取实例
Context.getContentResolver();

getContentResolver()方法可以获取一个ContentResolver的实例。

通过ContentResolver实例对数据进行操作

ContentResolver对数据也有CRUD这些操作。不过不同于SQLiteDatabase,这几个方法并不接受数据库表名,使用一个Uri参数代替了表名,

内容Uri给内容提供器中的数据建立了一个唯一标识符,由权限和路径两部分构成。

权限是用于对不同应用程序进行区分的,一般会采用程序包名来进行命名。
路径则是对同一应用程序的不同表做区分。

一般还要在头部加上协议声明,下面是一个示例:

content://com.example/app/provider/table

获取Uri对象的方法:

Uri uri = Uri.parse("content://com.example/app/provider/table");
  1. 查询

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

    同样返回一个Cursor对象。

    参数:uri(指定查询位置),projection(指定查询的列名),selection(指定where的约束条件),selectionArgs(为where中的占位符提供值),sortOrder(指定查询结果的排列顺序)。

  2. 增加

     //插入一条姓名hello年龄10岁的数据
     ContentValue values = new ContentValue();
     values.put("name", "hello");
     values.put("age", 10);
     getContentResolver.insert(uri, values);
    
  3. 删除

     //删除姓名为hello的数据
     getContentReslover.delete(uri, "name = ?", new String[] {"hello"});
    
  4. 更新

     //更新姓名
     ContentValue values = new ContentValue();
     values.put("name", "haha");
     getContentReslover.update(uri, values, "name = ? and age = ?", 
             new String[] {"haha", "10"});
    
小实践:读取系统联系人
  1. 获取Cursor对象

     Cursor cursor = null;
     try {
         //获取用来遍历的cursor对象
         cursor = getContentResolver.query(
             ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
             null,null,null,null);
     } catch (Exception e) {
         e.printStackTrace();
     } finally {
         if(cursor != null) {
             cursor.close();
         }
     }
    

    ContactsContract.CommonDataKinds.Phone.CONTENT_URI是我们要读取的Uri的封装变量,来自于ContactsContract.CommonDataKinds.Phone类。

  2. 遍历读取每行数据

     while(cursor.moveToNext()) {
         //获取联系人姓名
         String name  = cursor.getString(cursor.getColumnIndex(
             ContactsContract.CommonDataKinds.Phone.Number));
     }
    
  3. 对数据进行操作

     //操作吧。。。随意操作。
    

创建自己的内容提供器

  1. 创建内容提供器继承自ContentProvider

     public class MyProvider extends ContentProvider {
    
         @Override
         public boolean onCreate() {
             return false;
         }
     
         @Nullable
         @Override
         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
             return null;
         }
     
         @Nullable
         @Override
         public Uri insert(Uri uri, ContentValues values) {
             return null;
         }
     
         @Override
         public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
             return 0;
         }
     
         @Override
         public int delete(Uri uri, String selection, String[] selectionArgs) {
             return 0;
         }
     
         @Nullable
         @Override
         public String getType(Uri uri) {
             return null;
         }
     }
    

    这六个方法是必须要实现的

    onCreate():初始化内容提供器的时候调用,通常会在这里完成对数据库的创建和升级操作
    返回值对应了创建和升级操作的成功与否。只有当ContentResolver访问我们的数据时,内容提供器才会被初始化。

    query():uri指定查询表名,projection用于确定是哪些列,selection代表约束,selectionArgs代表约束里占位符的值,sortOrder确定查询返回数据的排列顺序。

    insert():uri指定插入表名,values携带数据,返回一个用于表示这条新纪录的Uri对象

    update():uri指定更新表名,valuse携带要更新的数据,selection代表约束,selectionArgs代表约束里占位符的值。返回更新的行号

    delete():uri指定更新表名,selection代表约束,selectionArgs代表约束里占位符的值。返回被删除的行数。

    getType():根据传入的内容Uri返回相应的MIME类型。

    query()

    这里query需要返回一个cursor,怎么去根据传入的参数去确认要返回的cursor呢,这里就用到了UriMatcher来对传入的uri进行匹配,剩下的内容就很容易了。

     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    
         Cursor cursor = null;
    
         switch (uriMatcher.match(uri)) {
             case TABLE1_DIR:
                 SQLiteDatabase database =
                 break;
             case TABLE1_ITEM:
                 break;
             case TABLE2_DIR:
                 break;
             case TABLE2_ITEM:
                 break;
             default:
                 break;
         }
         return cursor;
     }
    

    getType()

    getType是provider里面必须要实现的一个方法,这里返回一个MIME类型的字符串。
    public String getType(Uri uri) {
    switch (uriMatcher.match(uri)) {
    case TABLE1_DIR:
    return "vnd.android.cursor.dir/vnd.com.learn.app.provider.table1";
    break;
    case TABLE1_ITEM:
    return "vnd.android.cursor.item/vnd.com.learn.app.provider.table1";
    break;
    default:
    return null;
    break;
    }
    return null;
    } MIME类型由三个部分组成:

    1. 必须以vnd开头
    2. 如果uri是以路径结尾,则后接.android.cursor.dir/如果以ID结尾,则后接.android.cursor.item/
    3. 最后接上vnd.<authority>.<path>

    例如content://com.hello.app.provider.table这个Uri对应的MIME 字符串就是:
    vnd.android.cursor.dir/vnd.com.hello.app.provider.table

     public String getType(Uri uri) {
         switch (uriMatcher.match(uri)) {
             case TABLE1_DIR:
                 return "vnd.android.cursor.dir/vnd.com.learn.app.provider.table1";
                 break;
             case TABLE1_ITEM:
                 return "vnd.android.cursor.item/vnd.com.learn.app.provider.table1";
                 break;
             default:
                 return null;
                 break;
         }
         return null;
     }
    

实现跨程序数据共享

这一节写了很多代码,但是核心的点就是在于自定义的ContentProvider里面那六个方法分别的具体实现。

1.实现自己的Provider以后其他应用就可以通过这个provider来读取我们的数据。这里算是上面内容的一个结合吧。需要注意的有几个点:

query()方法里访问单条数据的时候可能需要用到Id,这里Uri对象提供了一个getPathSegmengts()方法,以"/"把uri内容分割放到字符串数组中。这样可以通过取数组[1]的位置得到id
最后还要在AndroidManifest.xml文件里注册内容提供器

<provider
    android:name="com.xx.xx.provider"
    android:authorities="com.xx.xxx.xx"
    android.exported="true"
</provider>

2.去操作上面那个provider提供的数据

使用getContentResolver()来进行各种操作。

总结

ContentProvider的存在使得应用程序之间数据共享与数据共享时的安全得以共存,不必担心数据泄露。

不知不觉写到了第七章,有过想放弃的时候,但是想想还是善始善终,不忘初心。记录下来学习的点点滴滴。嗯,就是这样。

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

推荐阅读更多精彩内容