ContentProvider是Android四大组件之一,其本质上是一个标准化的数据管道,它屏蔽了底层的数据管理和服务等细节,以标准化的方式在Android 应用间共享数据、数据交互,跨进程通信。
ContentProvider的底层是采用 Android中的Binder机制 具体请看文章 图文详解 Android Binder跨进程通信的原理
安全,访问简单,高效,统一了数据的访问方式。
该类需要继承Android提供的ContentProvider基类。然后实现ContentProvide的抽象方法,实现对数据的CRUD(create,retrieve,update,delete),还有onCreate和getType。
onCreate(),该方法在ContentProvider创建后会被调用,当其他应用程序第一次访问ContentProvide时,该ContentProvider会被创建出来,并立即回调该onCreate方法getType(Uri uri), 返回 当前Uri所代表的数据的MIME类型。如果该Uri对应数据可能包括多条记录,那么MIME类型字符串应该以 vnd.android.cursor.dir/开头;如果该Uri对应的数据只包含一条记录,那么返回MIME类型字符串应该以vnd.android.cursor.item/开头。注册的时候,与注册广播类似。
属性name指定ContentProvide实现类的类名;属性authorities是Uri标识,ContentProvide就是以这个Uri的形式对外提供数据,ContentResolve也是根据该Uri进行访问操作该应用的数据的,可以理解为网站的域名属性exported指定是否对外暴露数据,只有为true时,其他应用才可以访问该应用的数据,缺省值为true。通过调用Content的 getContentResolver() 方法获取 ContentResolver对象实例,其实ContentResolver的作用类似于HttpClient,获取对象后就可以根据Uri对应用的数据进行CRUD操作了。
与网站https://www.oracle.com/index.html的Uri的规则类似content://com.lzb.provide.myContentProvide:200/students 说明如下:
content://:协议部分,表示ContentProvider使用的协议,这个是固定的。com.lzb.provide.myContentProvide:URI 的标识,也是属性authorities定义的部分,系统就是通过这个部分找到要操作那个ContentProvide,为了保证URI标识的唯一性,它一般是一个完整的、小写的类名(包.小写的类名)。:200:端口号,Uri默认的端口是8080。students:资源部分(资源所在的路径),访问者可以访问不同的资源,这个是动态的;如果想要访问具体那行数据,可以在后面加上该行的ID,例如上述要该路径下的第1条记录,那么Uri可以写为content://com.lzb.provide.myContentProvide/students/1。作用:在ContentProvider 中注册URI,根据 URI 匹配 ContentProvider 中对应的数据表。 该类主要提供了如下两个方法:
public void addURI(String authority, String path, int code) 用于向UriMatcher注册Uri,其中参数authority与path组成一个Uri,参数code 是该Uri对应的标识码public int match(Uri uri) 根据前面注册的Uri返回其对应的标识码,如果在UriMatcher中找不到对应的Uri则返回-1。 // 步骤1:初始化UriMatcher对象 UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); //常量UriMatcher.NO_MATCH = 不匹配任何路径的返回码 // 即初始化时不匹配任何东西 // 步骤2:在ContentProvider 中注册URI(addURI()) int URI_CODE_a = 1; int URI_CODE_b = 2; matcher.addURI("cn.scu.myprovider", "user1", URI_CODE_a); matcher.addURI("cn.scu.myprovider", "user2", URI_CODE_b); // 若URI资源路径 = content://cn.scu.myprovider/user1 ,则返回注册码URI_CODE_a // 若URI资源路径 = content://cn.scu.myprovider/user2 ,则返回注册码URI_CODE_b // 步骤3:根据URI 匹配 URI_CODE,从而匹配ContentProvider中相应的资源(match()) @Override public String getType(Uri uri) { Uri uri = Uri.parse(" content://cn.scu.myprovider/user1"); switch(matcher.match(uri)){ // 根据URI匹配的返回码是URI_CODE_a // 即matcher.match(uri) == URI_CODE_a case URI_CODE_a: return tableNameUser1; // 如果根据URI匹配的返回码是URI_CODE_a,则返回ContentProvider中的名为tableNameUser1的表 case URI_CODE_b: return tableNameUser2; // 如果根据URI匹配的返回码是URI_CODE_b,则返回ContentProvider中的名为tableNameUser2的表 } }作用:操作 URI 核心方法有两个:withAppendedId()、parseId()
// withAppendedId()作用:向URI追加一个id Uri uri = Uri.parse("content://cn.scu.myprovider/user") Uri resultUri = ContentUris.withAppendedId(uri, 7); // 最终生成后的Uri为:content://cn.scu.myprovider/user/7 // parseId()作用:从URL中获取ID Uri uri = Uri.parse("content://cn.scu.myprovider/user/7") long personid = ContentUris.parseId(uri); //获取的结果为:7作用:观察 Uri引起 ContentProvider 中的数据变化 & 通知外界(即访问该数据访问者) 操作步骤如下: 1、注册ContentObserver 内容观察者 registerContentObserver 2、继承 ContentObserver 实现 onChange方法 3、当该URI的ContentProvider数据发生变化时,通知外界getContext().getContentResolver().notifyChange(uri, null); 4、解除观察者 getContentResolver().unregisterContentObserver(uri)。
为了降低上层业务对底层数据的依赖,需要增加一个数据访问层来解耦,ContentProvider充当的就是数据访问层的角色。内容提供者可以使用不同的方式来存储数据,数据可以被存放在数据库,文件,甚至是网络。
可以使用自定义ContentProvider。可以使用系统自带的ContentProvider,如音频、视频、图片、通讯录和短信。ContentResolver可以与ContentProvider在相同的进程间使用,但一般情况是跨进程使用。
参考链接 https://blog.csdn.net/lu1024188315/article/details/78303467 https://blog.csdn.net/carson_ho/article/details/76101093
更详细的的解析 https://blog.csdn.net/luoshengyang/article/details/6946067