上海做公司网站,网站做产品的审核,php网站开发外文,网站建设哪个公司好知乎在 Android 系统的四大核心组件中#xff0c;activity负责用户界面交互#xff0c;service承担后台服务工作#xff0c;receiver作为广播接收器传递系统或应用间的消息#xff0c;它们在日常开发中被频繁使用。而content provider虽然使用频率相对较低#xff0c;但在特定…在 Android 系统的四大核心组件中activity负责用户界面交互service承担后台服务工作receiver作为广播接收器传递系统或应用间的消息它们在日常开发中被频繁使用。而content provider虽然使用频率相对较低但在特定开发场景中它却是不可或缺的关键角色。为了全面且深入地掌握这个组件接下来将对其进行更为细致、全面的系统性整理和学习。
什么是 content provider
content provider是 Android 平台精心设计的一种高效的数据共享机制它凭借独特的特性在数据共享领域发挥着重要作用主要具有以下特点
1. 跨应用数据共享
这是 Android 中唯一原生支持安全跨应用数据共享的机制其重要性不言而喻。以通讯录应用为例它可以通过Content Provider将联系人数据有安全保障地提供给其他应用访问。比如当某个办公类应用需要获取用户联系人信息进行快速拨号或发送邮件时就可以通过Content Provider实现既保证了数据的安全性又实现了不同应用间的数据交互。
2. 使用场景 私密数据共享主要适用于需要跨应用共享的私密数据像联系人信息、短信记录等。这些数据涉及用户隐私通过Content Provider可以在严格的安全管控下实现共享确保数据不会被非法访问。 特殊需求场景当对效率和网络限制有特殊需求时Content Provider也能大显身手。例如在一些对网络依赖较小的离线应用中需要快速访问本地存储的大量数据Content Provider的本地访问特性可以极大提升数据访问效率。 典型应用场景 访问系统相册开发图片编辑类应用时需要获取系统相册中的图片此时就可以通过Content Provider来实现对相册数据的读取和操作。 获取联系人信息如前文所述很多应用需要获取联系人数据用于不同功能。 共享自定义数据库当多个应用需要共享同一份自定义的结构化数据比如企业内部的员工信息数据库就可以借助Content Provider实现数据共享。
3. 工作机制 CRUD 操作模式采用类似数据库的 CRUD增删改查操作模式使得对数据的操作简洁明了且符合开发者的习惯。无论是创建新的数据记录、删除不再需要的数据还是更新已有数据或查询特定条件的数据都可以通过相应的操作方法轻松实现。 URI 标识数据通过 URI统一资源标识符来标识要操作的数据。每个Content Provider都有一个唯一的 URI类似于数据库中的表名通过这个 URI 可以精确地定位到需要操作的数据集合。例如content://contacts/people就是用于访问联系人数据的 URI。 ContentResolver 访问接口使用ContentResolver作为客户端访问接口。客户端应用通过ContentResolver对象与Content Provider进行交互ContentResolver会根据 URI 找到对应的Content Provider并执行相应的操作请求。
4. 与服务端请求的异同 相似之处都需要通过 URI/URL 定位资源都支持查询和更新操作。无论是访问Content Provider中的数据还是向服务端请求数据都需要明确指定资源的位置并且都可以对数据进行查询和更新操作。 不同之处Content Provider工作在本地不需要网络连接效率更高。例如获取联系人数据既可通过Content Provider本地也可以通过 API 从服务端获取。通过Content Provider在本地直接获取数据避免了网络请求带来的延迟和不稳定因素能够快速响应用户的操作而通过服务端 API 获取数据则需要依赖网络连接在网络环境不佳时数据获取的速度和稳定性都会受到影响。
5. 安全机制 权限系统控制通过 Android 权限系统控制访问只有具备相应权限的应用才能访问Content Provider中的数据。例如要访问联系人数据应用必须在AndroidManifest.xml文件中声明READ_CONTACTS权限。 读写权限分离支持读写权限分离可以分别设置读取数据和写入数据的权限进一步增强数据的安全性。比如有些应用只需要读取联系人数据就可以只授予其读取权限而不授予写入权限。 精细化 URI 权限控制可设置精细化的 URI 权限控制不仅可以对整个Content Provider设置权限还可以针对具体的 URI 路径设置不同的权限实现更细致的数据访问控制。
在实际开发中Content Provider通常与SQLite数据库配合使用为数据提供统一的访问接口。SQLite数据库负责存储和管理数据而Content Provider则将这些数据以一种标准化、安全化的方式共享给其他应用。在 Android 10 及更高版本中Google 对Content Provider的权限控制和安全机制做了进一步强化以更好地保护用户数据安全。
为什么要使用 Content Provider?
content Provider作为结构化的数据存储和共享方案同时支持 CRUD 操作和读写分离对于共享结构化数据来说十分合适。其主要功能在于跨应用间的数据共享在很多场景下都能发挥重要作用。
一方面对于应用间共享文件可以使用FileProvider这种轻量级的封装进行共享。而对于共享结构化数据Content Provider最大的优势在于支持数据库的 CRUD 操作。它能够将复杂的数据库操作封装起来以统一的接口提供给其他应用使得不同应用之间的数据交互更加便捷和规范。
另一方面我们访问系统的数据也是通过Content Provider进行访问的。系统中的各种数据如联系人、短信、相册等都通过Content Provider对外提供访问接口。开发者只需要遵循相应的规则使用ContentResolver就可以轻松获取和操作这些系统数据极大地简化了开发过程提高了开发效率。
开发中为什么不使用 Content Provider
在实际开发过程中content provider相较于其它组件使用频率不是特别高。尤其当业务没有对外数据交互需求时对于应用内的数据共享使用SharePreferences、Room等方式显然更加方便。SharePreferences适用于存储简单的键值对数据如用户的配置信息、登录状态等Room则是 Google 推出的一款强大的数据库框架它对SQLite进行了封装提供了更加简洁、高效的操作方式非常适合应用内的数据存储和管理。
对于简单数据的传递自定义广播也能达到相应的要求。自定义广播可以在应用内快速传递消息和简单的数据实现组件之间的通信。而使用Content Provider则需要自定义实现 CRUD 操作开发过程相对复杂需要更多的代码和时间成本。
此外在 Android 10 以后Android 对跨应用共享数据有了更严格的要求。例如在开发中将应用target升到了 Android 10 以上可能会发现应用无法读取对应 url 的数据即便使用adb构造查询可以读到数据。这是因为 Android 10 引入了更严格的权限管理机制应用需要在清单文件中明确声明对目标应用数据的访问权限。最后排查发现需要在AndroidManifest.xml文件中添加如下代码
queries
package android:namecom.example.targetapp /
/queries添加上述代码后应用才能正常读取对应的数据这无疑增加了开发的难度和复杂性。
如何定义和使用 Content Provider?
定义 Content Provider
创建 Content Provider 类
继承 ContentProvider 类并实现其核心方法
import android.content.*
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.net.Uriclass MyContentProvider : ContentProvider() {private lateinit var dbHelper: MyDatabaseHelperprivate val uriMatcher UriMatcher(UriMatcher.NO_MATCH)companion object {const val AUTHORITY com.example.myproviderconst val TABLE_NAME my_tableval CONTENT_URI: Uri Uri.parse(content://$AUTHORITY/$TABLE_NAME)}init {uriMatcher.addURI(AUTHORITY, TABLE_NAME, 1)}override fun onCreate(): Boolean {dbHelper MyDatabaseHelper(context)return true}override fun query(uri: Uri,projection: ArrayString?,selection: String?,selectionArgs: ArrayString?,sortOrder: String?): Cursor? {val db dbHelper.readableDatabasereturn db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder)}override fun insert(uri: Uri, values: ContentValues?): Uri? {val db dbHelper.writableDatabaseval id db.insert(TABLE_NAME, null, values)context?.contentResolver?.notifyChange(uri, null)return Uri.parse($CONTENT_URI/$id)}override fun update(uri: Uri,values: ContentValues?,selection: String?,selectionArgs: ArrayString?): Int {val db dbHelper.writableDatabaseval count db.update(TABLE_NAME, values, selection, selectionArgs)context?.contentResolver?.notifyChange(uri, null)return count}override fun delete(uri: Uri, selection: String?, selectionArgs: ArrayString?): Int {val db dbHelper.writableDatabaseval count db.delete(TABLE_NAME, selection, selectionArgs)context?.contentResolver?.notifyChange(uri, null)return count}override fun getType(uri: Uri): String? {return when (uriMatcher.match(uri)) {1 - vnd.android.cursor.dir/vnd.$AUTHORITY.$TABLE_NAMEelse - null}}
}注册 Content Provider
在 AndroidManifest.xml 中添加
providerandroid:name.MyContentProviderandroid:authoritiescom.example.myproviderandroid:exportedtrueandroid:grantUriPermissionstruemeta-dataandroid:nameandroid.support.FILE_PROVIDER_PATHSandroid:resourcexml/file_paths /
/provider使用 Content Provider
查询数据
val resolver: ContentResolver context.contentResolver
val uri Uri.parse(content://com.example.myprovider/my_table)
val cursor resolver.query(uri, null, null, null, null)cursor?.use {while (it.moveToNext()) {// 处理查询结果}
}插入数据
val resolver: ContentResolver context.contentResolver
val uri Uri.parse(content://com.example.myprovider/my_table)
val values ContentValues().apply {put(column1, value1)put(column2, value2)
}
val insertedUri resolver.insert(uri, values)更新数据
val resolver: ContentResolver context.contentResolver
val uri Uri.parse(content://com.example.myprovider/my_table)
val values ContentValues().apply {put(column1, new_value1)
}
val count resolver.update(uri, values, column2 ?, arrayOf(value2))删除数据
val resolver: ContentResolver context.contentResolver
val uri Uri.parse(content://com.example.myprovider/my_table)
val count resolver.delete(uri, column1 ?, arrayOf(value1))这些步骤展示了如何定义和使用 Content Provider 进行数据操作。开发过程中可根据业务需求修改。