<第一行代码>chapter7 ContentProvider

内容提供器

思维导图

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

<第一行代码>chapter7 ContentProvider_第1张图片
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..

    例如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文件里注册内容提供器


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

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

总结

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

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

你可能感兴趣的:(<第一行代码>chapter7 ContentProvider)