1)谈谈你对ContentProvider的理解
说说ContentProvider、ContentResolver、ContentObserver 之间的关系
2)请介绍下ContentProvider 是如何实现数据共享的?
3)ContentProvider的权限管理(解答:读写分离,权限控制-精确到表级,URL控制)
4)Android系统为什么会设计ContentProvider?

首先,官网的基本链接:
https://developer.android.com/guide/topics/providers/content-provider-basics
https://developer.android.com/guide/topics/providers/content-provider-creating

一. 对于ContentProvider的理解

ContentProvider 内容提供者,用于对外提供数据
ContentResolver.notifyChange(uri)发出消息
ContentResolver 内容解析者, 用于获取内容提供者提供的数据
ContentObserver 内容***, 可以监听数据的改变状态
ContentResolver.registerContentObserver() 监听消息

query流程图

设计ContentProvider的主要目的是供其他应用使用。不同应用可共享存取数据,这些应用使用提供程序客户端对象来访问提供程序。提供程序与提供程序客户端共同提供一致的标准数据接口,该接口还可处理跨进程通信并保护数据访问的安全性。

应用从具有 ContentResolver 客户端对象的内容提供程序访问数据。此对象具有调用提供程序对象ContentProvider的某个具体子类的实例)中同名方法的方法。 ContentResolver 方法可提供持续存储的基本“CRUD”(创建、检索、更新和删除)功能。供开发者调用的 (如视频,音频,图片,通讯录等)

客户端应用进程中的 ContentResolver 对象和拥有提供程序的应用中的 ContentProvider 对象可自动处理跨进程通信。 ContentProvider 还可充当其数据存储区和表格形式的数据外部显示之间的抽象层。

公共的URI

  • 每个ContentProvider都有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
  • Android所提供的ContentProvider都存放在android.provider包当中。
二. 实现步骤
1. 定义一个 CONTENT_URI 常量

// CONTENT_URI 的字符串必须是唯一
public static final Uri CONTENT_URI = Uri.parse("content://com.WangWeiDa.MyContentprovider");
// 如果有子表,URI为:
public static final Uri CONTENT_URI = Uri.parse("content://com.WangWeiDa.MyContentProvider/users");

2. 定义一个继承自ContentProvider的类

public class MyContentProvider extends ContentProvider { ... }

3. 实现ContentProvider的所有方法

先写一个常量类

public class MyContentProviderMetaData {
   //URI的指定,此处的字符串必须和声明的authorities一致
   public static final String AUTHORITIES = "com.zhuanghongji.app.MyContentProvider";
   //数据库名称
   public static final String DATABASE_NAME = "myContentProvider.db";
   //数据库的版本
   public static final int DATABASE_VERSION = 1;
   //表名 
   public static final String USERS_TABLE_NAME = "user";
   
   public static final class UserTableMetaData implements BaseColumns{
       //表名
       public static final String TABLE_NAME = "user";
       //访问该ContentProvider的URI
       public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITIES + "/user");
       //该ContentProvider所返回的数据类型的定义
       public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.myprovider.user";
       public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.myprovider.user";
       //列名
       public static final String USER_NAME = "name";
       //默认的排序方法
       public static final String DEFAULT_SORT_ORDER = "_id desc";
   }
}
public class MyContentProvider extends ContentProvider {
   //访问表的所有列
   public static final int INCOMING_USER_COLLECTION = 1;
   //访问单独的列
   public static final int INCOMING_USER_SINGLE = 2;
   //操作URI的类
   public static final UriMatcher uriMatcher;
   //为UriMatcher添加自定义的URI
   static{
       uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
       uriMatcher.addURI(MyContentProviderMetaData.AUTHORITIES,"/user",
           INCOMING_USER_COLLECTION);
       uriMatcher.addURI(MyContentProviderMetaData.AUTHORITIES,"/user/#",
           INCOMING_USER_SINGLE);
   }
   
   private DatabaseHelper dh;
   //为数据库表字段起别名
   public static HashMap userProjectionMap;
   static
   {
       userProjectionMap = new HashMap();
       userProjectionMap.put(UserTableMetaDa***serTableMetaData._ID);
       userProjectionMap.put(UserTableMetaData.USER_NAME, UserTableMetaData.USER_NAME);
   }
   /**
   * 删除表数据
   */
   @Override
   public int delete(Uri uri, String selection, String[] selectionArgs) {
       System.out.println("delete");
       //得到一个可写的数据库
       SQLiteDatabase db = dh.getWritableDatabase();
       //执行删除,得到删除的行数
       int count = db.delete(UserTableMetaData.TABLE_NAME, selection, selectionArgs);
       
       return count;
   }
   
   /**
   * 数据库访问类型
   */
   @Override
   public String getType(Uri uri) {
       System.out.println("getType");
       //根据用户请求,得到数据类型
       switch (uriMatcher.match(uri)) {
           case INCOMING_USER_COLLECTION:
               return MyContentProviderMetaData.UserTableMetaData.CONTENT_TYPE;
           case INCOMING_USER_SINGLE:
               return MyContentProviderMetaData.UserTableMetaData.CONTENT_TYPE_ITEM;
           default:
               throw new IllegalArgumentException("UnKnown URI"+uri);
       }
   }
   
   /**
   * 插入数据
   */
   @Override
   public Uri insert(Uri uri, ContentValues values) {
       //得到一个可写的数据库
       SQLiteDatabase db = dh.getWritableDatabase();
       //向指定的表插入数据,得到返回的Id
       long rowId = db.insert(UserTableMetaData.TABLE_NAME, null, values);
       if(rowId > 0){ // 判断插入是否执行成功
           //如果添加成功,利用新添加的Id和
           Uri insertedUserUri = ContentUris.withAppendedId(UserTableMetaData.CONTENT_URI, rowId);
           //通知***,数据已经改变
           getContext().getContentResolver().notifyChange(insertedUserUri, null);   
           return insertedUserUri;
       }   
       return uri;
   }
   
   /**
   * 创建ContentProvider时调用的回调函数
   */
   @Override
   public boolean onCreate() {
       System.out.println("onCreate");
       //得到数据库帮助类
       dh = new DatabaseHelper(getContext(),MyContentProviderMetaData.DATABASE_NAME);
       return false;
   }
   
   /**
   * 查询数据库
   */
   @Override
   public Cursor query(Uri uri, String[] projection, String selection,
   String[] selectionArgs, String sortOrder) {
       //创建一个执行查询的Sqlite
       SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
       //判断用户请求,查询所有还是单个
       switch(uriMatcher.match(uri)){
           case INCOMING_USER_COLLECTION:
               //设置要查询的表名
               qb.setTables(UserTableMetaData.TABLE_NAME);
               //设置表字段的别名
               qb.setProjectionMap(userProjectionMap);
               break;
           case INCOMING_USER_SINGLE:
               qb.setTables(UserTableMetaData.TABLE_NAME);
               qb.setProjectionMap(userProjectionMap);
               // 追加条件,getPathSegments()得到用户请求的Uri地址截取的数组,
               // get(1)得到去掉地址中/以后的第二个元素
               qb.appendWhere(UserTableMetaDa***ri.getPathSegments().get(1));
               break;
       }
       //设置排序
       String orderBy;
       if(TextUtils.isEmpty(sortOrder)){
           orderBy = UserTableMetaData.DEFAULT_SORT_ORDER;
       } else {
           orderBy = sortOrder;
       }
       //得到一个可读的数据库
       SQLiteDatabase db = dh.getReadableDatabase();
       //执行查询,把输入传入
       Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
       //设置监听
       c.setNotificationUri(getContext().getContentResolver(), uri);
       return c;
   }
   
   /**
   * 更新数据库
   */
   @Override
   public int update(Uri uri, ContentValues values, String selection,
   String[] selectionArgs) {
       System.out.println("update");
       //得到一个可写的数据库
       SQLiteDatabase db = dh.getWritableDatabase();
       //执行更新语句,得到更新的条数
       int count = db.update(UserTableMetaData.TABLE_NAME, values, selection, selectionArgs);
       return count;
   }
}
4. 在AndroidMinifest.xml中进行声明
<provider 
    android:name=".MyContentProvider"
   android:authorities="com.zhuanghongji.app.MyContentProvider" />
三. ContentProvider的权限管理

https://www.cnblogs.com/622698abc/p/6033080.html