前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android必知必会的四大组件--ContentProvider

Android必知必会的四大组件--ContentProvider

作者头像
ClericYi
发布2020-06-23 15:18:58
5310
发布2020-06-23 15:18:58
举报
文章被收录于专栏:ClericYi's Blog

前言

作为四大组件之一,它的地位绝对不容许轻视的。但是我们在哪里有用到过他呢?其实很多场景都有,比如说你在使用app时,是不是经常的会询问你是否开启通讯录的访问,如果你同意了,这个时候ContentProvider就发挥了他的作用。

使用方法

以下通过对通讯录的操作让读者来更清晰的了解。但是共享的数据不应该被我们随意的更改,如果有这样的需要,把这些数据存储在本地,然后再进行这样的操纵更为合适,所以下方的演示代码只包含了查询的功能。不过因为调用外部的数据,一般来说需要权限申请。

我已经在 helper 中集成了权限申请的工具类。

代码语言:javascript
复制
// 数据查询
try (Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null)) {
        while (cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                Log.e(TAG, name + " ;" + number);
            }
} catch (Exception e) {
            e.printStackTrace();
}

文件共享的基础

其实在ContentProvider中使用的通信机制依旧是Binder,而文件定位则是通过URI的方式来完成,所以主讲的一部分内容就是URI的格式解析。

URI

URI(Uniform Resource Identifier)即统一资源标识符,是一个用于标识某一互联网资源名称的字符串

代码语言:javascript
复制
格式:[schema:][//host:port][path][?query]

这一个URI的格式,为了方便起见,我们直接拿一个域名来分析它。

》》例题《《

代码语言:javascript
复制
链接地址:
https://tieba.baidu.com/p/6134071950?fr=ala0&pstaala=1&tpl=5&fid=18816&isgod=0&red_tag=1269271108
  1. schema:https,也就是协议
  2. host:tieba.baidu.com,域名地址
  3. port:默认80,端口号
  4. path:p/6134071950,文件路径/控制器路径
  5. query:fr=ala0&pstaala=1&tpl=5&fid=18816&isgod=0&red_tag=1269271108,就是我们javaWeb中的一些请求数据。

当然在我们的ContentProvider存在一定的偏差。

代码语言:javascript
复制
文件位置:
content://com.clericyi.file/message/id
  1. 主题(Schema):content://,这是Android的固定路径
  2. 授权信息(Authority):com.clericyi.file,也就是用于标示唯一的ContentProvider
  3. 表名(path):message,也就是对应的表名
  4. 记录(id):对应表中的数据,没有指定时数据全部返回。

MIME类型

MIME(Multipurpose Internet Mail Extensions)即多用途互联网邮件扩展类型,是指定某种扩展名的文件用什么应用程序来打开的方式类型。当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

帮助工具

UriMatcher

这是一个内置的URI工具,他一共只提供了两个开放方法addURI()、match(),这是一个用于帮助匹配ContentProvider中URI的方法,针对的是除去id前半段匹配。

代码语言:javascript
复制
// 用法
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
String authority = "com.clericyi.file";
String path = "message";
int URI_CODE = 1;
// 将URI和URI_CODE关联
uriMatcher.addURI(authority, path, URI_CODE);
// 用于获取对应的URI_CODE
uriMatcher.match(Uri.parse("content://com.clericyi.file/message"))

ContentUris

同样是一个内置的工具类,提供的方法有parseId()、appendId()、withAppendedId()、removeId(),不过从这几个方法可以看出,操作主要的针对的就是id了。

代码语言:javascript
复制
Uri uri = Uri.parse("content://com.clericyi.file/message");
// 连接id
uri = ContentUris.withAppendedId(uri, URI_CODE);
// 去除id
uri = ContentUris.removeId(uri);
// 获取id
long num = ContentUris.parseId(uri);
// 追加id
Uri.Builder appendIdUri = ContentUris.appendId(uri,1);

ContentObserver类

数据访问者,当发生增删改的任务的时候,造成数据变化时,就会触发这个类。

代码语言:javascript
复制
// 通过ContentResolver类进行注册,并指定需要观察的URI
getContentResolver().registerContentObserver(uri);
//当数据发生变化时,通知外界
public class XXXContentProvider extends ContentProvider {
  public Uri insert(Uri uri, ContentValues values) {
    // 对数据库发生操作
    // 。。。。。。。
    // 通知访问者
    getContext().getContentResolver().notifyChange(uri, null);
  }
}
// 解除观察者(存在注册,自然的就要有对应的接触操作)
getContentResolver().unregisterContentObserver(uri)

ContentProvider代码流程导读

工作流程:

从上文中的电话簿号码查询入手:

(1)获取一个ContentResolver,并调用query(),内部参数很多,基本和数据库查询的参数保持一致。

(2)在query()方法中会调用到acquireUnstableProvider(uri)的方法,而返回值IContentProvider,对应就是一个Binder机制

(3)内部通过对uri的一些解析,找得到对应的文件,然后转化成Cursor游标

(4)通过游标的滑动读取,就转化成了我们的数据

query()内部参数分析

  • uri:位置暴露的唯一表示。
  • projection:返回列(字段)
  • selection:设置条件,相当于数据库中的where
  • selectionArgs:和selection联合使用,用于替换selection中的 ?
  • sortOrder:排列顺序,相当于数据库中的order by

全部参数使用实例:

代码语言:javascript
复制
contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI
  , new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME}
  , android.provider.ContactsContract.Contacts.DISPLAY_NAME + "=?"
  , new String[]{"小易"}
  , android.provider.ContactsContract.Contacts.DISPLAY_NAME + " DESC"); // 中间存在空格,默认为ASC,升序。

当然这个也不是ContentProvider的唯一一个任务,他还有如下的几个必须要进行重写的方法:

代码语言:javascript
复制
// 增删改查的细节不再多说
public Uri insert(Uri uri, ContentValues values)
public int delete(Uri uri, String selection, String[] selectionArgs)
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,  String sortOrder) 
// 
public boolean onCreate() //这个函数运行在UI线程中,不要进行耗时操作
public String getType(Uri uri) // 获取MIME类型

上文我们知道了一件事情,就是完成数据获取的其实并不是我们的ContentProvider,它会先去获取一个ContentResolver类,那我们接下来的研究对象就应该是ContentResolver了。

ContentResolver

ContentResolver可以统一管理不同 ContentProvider间的操作。

Q1:为什么要使用通过ContentResolver类从而与ContentProvider类进行交互,而不直接访问ContentProvider类?

对于这正常的一个应用一般都是要使用很多个ContentProvider,若需要了解每个ContentProvider的不同实现从而再完成数据交互难度且复杂成本极高,加上了一个ContentResolver类对所有的ContentProvider进行统一管理,就弱化了这些难度。

提供的方法和ContentProvider是一致的:

代码语言:javascript
复制
// 外部进程向ContentProvider中添加数据
public Uri insert(Uri uri, ContentValues values)

// 外部进程删除ContentProvider中的数据
public int delete(Uri uri, String selection, String[] selectionArgs)

// 外部进程更新ContentProvider中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)

// 外部应用获取ContentProvider中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

ContentProvider的优点

(1) 安全

ContentProvider为应用间的数据交互提供了一个安全的环境:允许把自己的应用数据根据需求开放给 其他应用 进行 增、删、改、查,而不用担心因为直接开放数据库权限而带来的安全问题。

(2) 访问简单 & 高效

对比于其他对外共享数据的方式,数据访问方式会因数据存储的方式而不同:

  • 采用 文件方式 对外共享数据,需要进行文件操作读写数据;
  • 采用 Sharedpreferences 共享数据,需要使用 sharedpreferences API读写数据

这使得访问数据变得复杂 & 难度大。

  • 而采用ContentProvider方式,其 解耦了 底层数据的存储方式,使得无论底层数据存储采用何种方式,外界对数据的访问方式都是统一的,这使得访问简单 & 高效

总结

参考文献:Android:关于ContentProvider的知识都在这里了! ContentProvider的Demo,Carson_Ho大佬也已经建立了仓库。 https://www.jianshu.com/p/ea8bc4aaf057

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DevGW 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • (1) 安全
  • (2) 访问简单 & 高效
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档