目录
内容提供者(contentProvider)
Content Provider用于管理应用的数据,并提供数据的访问和共享。它可以使应用之间共享数据成为可能,其他应用可以通过Content Provider访问和操作特定应用的数据,同时Content Provider可以对数据进行权限控制和管理。
-
为什么设计ContentProvider
-
隐藏数据实现方式,提供统一的接口,使用者无需关心这些数据从哪里来的(SQlite数据库、XML、sharedpreferences存储、文件、网络),无需关注存储的实现方式
-
封装了跨进程共享的逻辑,只需要uri即可访问数据,提供跨进程共享的一种方式,用来数据共享的一种机制,进程间通信,由系统来管理 ContentProvider 的创建、生命周期及访问的线程分配,简化我们在应用间共享数据( 进程间通信 )的方式。我们只管通过 ContentResolver 访问 ContentProvider 所提示的数据接口,而不需要担心它所在进程是启动还是未启动。
-
数据更新机制,当一个应用修改了数据后,可以通知其他应用程序
-
更好的数据访问权限管理,可以选择控制哪一部分的数据进行共享,不同的uri可以对应不同的权限,从而保证隐私数据的安全性
-
所以为什么要用ContentProvider?
功能需求:一个应用需要访问另一个应用的数据库表数据
实际情况:一个应用的数据库文件是应用私有的,其他应用不能直接访问,参考应用私有数据区域部分内容
-
实际生活中的例子
-
日程安排、日程提醒等信息,比如咪咕视频设置赛事提醒到日历中
-
获取通讯录列表,来发现平台共同好友,如抖音、小红书等
-
读取相册照片二次编辑
-
互动萌宠对外提供萌宠列表(存储方式:XML、sharedpreferences存储) 看项目代码
-
SpaceSaver(应用可卸载)中对应用卸载信息进行存储(存储方式:SQLite数据库)看项目代码
Android框架自带的ContentProvider:
Android框架内附带了部分基础的内容提供者,用于存储常用数据,如联系人信息,日历信息和媒体文件,如联系人、日历、短信、音频、视频、相册等
android.provider - Android中文版 - API参考文档 (apiref.com)
-
contentProvider数据共享流程
组成部分
-
内容提供者 ContentProvider
-
内容接收者 ContentResolver
-
内容观察者 ContentObserver
ContentProvider 程序以一个或多个表的形式将数据呈现给外部应用,这些表与关系型数据库中的表类似。行表示提供程序收集的某种类型数据的实例,行中的每一列表示为一个实例所收集的单个数据
-
基本使用方式
-
准备数据源
为数据设计原始存储
-
文件数据:通常存储在文件中的数据,如照片、音频或视频。将文件存储在应用的私有空间内。提供程序可以为其他应用发出的文件请求提供文件句柄。
-
结构化数据:通常存储在数据库、数组或类似结构中的数据。以兼容行、列表的形式存储数据。行表示实体,如人员或库存商品。列表示实体的某项数据, 如人员姓名或商品价格。此类数据通常存储在 SQLite 数据库中,但也可以使用任何类型的持久存储,也可用Room DataBase等方式。
-
创建数据库:App A提供数据,初始化一个Sqlite数据库为数据源
-
实现数据存储和检索的逻辑,通常涉及到数据库的操作,以本地SqLite数据库举例
-
-
网络数据:可直接访问网络的数据,也可以访问网络的数据同步至本地数据存储(如数据库),然后以表格或文件的形式提供这类数据。
注意事项:
-
不是必须使用数据库来实现存储区。
-
可以多种存储组合使用。
-
表格数据应始终有“主键”列,提供程序会将其作为每行的唯一数值加以 维护。可以使用此值将某行链接到其他表中的相关行(将其用作“外键”)。
-
创建Contentprovider
-
自定义一个类实现ContentProvider类,重写其方法,query、insert、update、delete、onCreate、getType
-
在AndroidManifest.xml中声明ContentProvider
-
提供适当的URI,以便于外部应用程序通过ContentResolver与之交互
-
可以定义权限,如通讯录 ContentProvider 程序定义的"android.permission.READ_CONTACTS 权 限 , 我 们 在 读 取 通 讯 录 联 系 人 信 息 的 时 候 需 要 加 上 :
<user-permission android:name="android.permission.READ_CONTACTS">权限
注意事项
-
创建提供程序后,Android 系统会立即调用onCreate() 方法,onCreate运行在 UI 线程,query、insert、delete、update运行在线程池中的工作线程,避免在 onCreate() 中执行冗长的操作。可以将初始化数据库任务推迟到实际需要时执行。
-
调用这四个方法并不会阻塞ContentProvider 所在进程的主线程,但可能会阻塞调用者所在的进程的UI线程
-
这些方法(onCreate() 除外)均可由多个线程同时调用,因此它们必须是线程安全的方法。
-
使用ContentResolver获取数据
-
AndroidManifest.xml中定义权限
<queries>
<provider android:authorities="com.example.contentprovidertest.provider"/>
</queries>
-
在所有继承Context的类中,都可以通过调用getContentResolver()来获得ContentResolver
-
通过正确的url调用增删改查方法
-
查询:ContentResolver.query()
-
插入:ContentResolver.insert()
-
更新:ContentResolver.update()
-
删除:ContentResolver.delete()
-
观察ContentProvider的数据变化
-
由ContentResolver.registerContentObserver注册和解除注册来实现
-
ContentProvider具有通知机制,可以在数据发生变化时通知订阅了该数据的客户端。这是通过ContentObserver类来实现的,客户端可以注册一个ContentObserver来监听数据的变化事件。
-
provider清单文件配置详解
<providerandroid:authorities="list" android:enabled=["true" | "false"] android:exported=["true" | "false"] android:grantUriPermissions=["true" | "false"] android:icon="drawable resource" android:initOrder="integer" android:label="string resource" android:multiprocess=["true" | "false"] android:name="string" android:permission="string" android:process="string" android:readPermission="string" android:syncable=["true" | "false"] android:writePermission="string"> . . . </provider>
属性
介绍
android:authorities
声明内容提供器的授权列表,多个授权时,用分号分离。名称采用java样式的命名规则,如:com.example.provider.cartoonprovider
android:name
完整的包名+类名
android:enabled
用于指定这个内容提供器是否能够被系统安装。设置为true,则可以安装。默认为true
android:exported
指定该内容提供器是否能够被其他的应用程序组件使用
android:permission
设定客户端在读写内容提供器的数据时必须要有的权限的名称
android:readPermission
用于设置查询内容提供器的数据时,客户端所必须要有的权限
android:writePermission
用于设置修改内容提供器的数据时,客户端所必须要有的权限
android:icon
定义一个代表内容提供器的图标,默认使用application中的icon属性
android:label
定义一个用户可读的标签,默认使用application中的label属性
android:initOrder
定义内容提供器应该被实例化的顺序:接受一个整数值,数字越小越先被初始化,考虑系统并发性,不建议使用,可能用于内容提供器间有相互的依赖时
android:multiprocess
设定是否能够在每个使用该内容提供器的客户端进程中都创建一个内容提供器的实例,避免了进程间通信的开销
android:grantUriPermission
设定那些对内容提供的数据没有访问权限的访问者,是否能够被授予访问的权限,这个权限是临时性的,只在 Activity 或 Service 处于活动状态时有效,谨慎使用,可能带来安全性问题,可以配合<grant-uri-permission> 标签用于更精细地控制哪些 URI 可以被授予访问权限。这个标签可以包含 android:path, android:pathPrefix, 或 android:pathPattern 属性来匹配 URI 的路径部分。