跨程序共享数据,探究 ContentProvider

介绍

ContentProvider 主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。目前,使用 ContentProvider 是 Android 实现跨程序共享数据的标准方式

不同于 文件存储和 SharedPreferences 存储中的两种全局可读写操作模式,ContentProvider 可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄露的风险

ContentProvider 的用法一般有两种:一种是使用现有的 ContentProvider 读取和操作相应程序中的数据;另一种是创建自己的 ContentProvider 给程序的数据提供外部访问接口

ContentResolver 的基本用法

知识储备

对于每一个应用程序来说,想要访问 ContentProvider 中共享的数据,就要借助 ContentResolver 类,可以通过 getContentResolver() 方法来获取该类实例。ContentResolver 中提供了一系列方法对数据进行增删改查:insert()添加数据;update()更新数据;delete()删除数据;query()查询数据

接收一个 Uri 参数,被称为 内容 URI。 内容 URI 给 ContentProvider 中的数据建立了唯一标识符,它由 authoritypath 组成。authority是用于对不同的应用程序做区分的,一般为了避免冲突会采用包名的方式进行命名。例如某个应用的包名是 com.example.app ,那么该应用对应的 authority 可命名为 com.example.app.provider。path则是用于对同一应用程序中不同的表做区分的,通常会添加到 authority 后边。比如某个应用的数据库中有两张表 table1 和 table2,这时可以将 path 分别命名为 /table1 和 /table2,然后把 authority 和 path 进行组合,内容URI 就变成了 com.example.app.provider/table1 和com.example.app.provider/table2 。最后需要在字符串头部加上协议声明。因此内容 URI 最标准的格式为:

content://com.example.app.provider/table1
content://com.example.app.provider/table2

然后需要把它解析成 Uri 对象才可以作为参数传入:

val uri = Uri.parse("content://com.example.app.provider/table1")

现在可以使用这个 Uri 对象查询 table1 表中的数据了:

val cursor = contentResolver.query(
	uri,
	projection,
	selection,
	selectionArgs,
	sortOrder
)

参数说明:
uri:指定查询某个应用程序下的某一张表
projection:指定查询的列名
selection:指定 where 的约束条件
selectionArgs:为 where 中占位符提供具体的值
sortOrder:指定查询结果的排序方式

查询完成后仍是 Cursor 对象,读取方式如下:

while(cursor.moveToNext()){
   
	val column1 = cursor.getString(cursor.getColumnIndex("column1"))
	val column2 = cursor.getInt(cursor.getColumnIndex("column2"))
}
cursor.cloase()

增加一条数据可以这么写:

val values = contentValuesOf("column1" to "text","column2" to 1)
contentResolver.insert(uri,values)

如果想要更新这条添加的数据,把 column1 的值清空,可以借助 ContentResolver 的 update() 方法实现:

val values = contentValuesOf("column1" to "")
contentResolver.update(uri,values,"column1 = ? and column2 = ?",arrayOf("text","1"))

注意,上述代码使用了 selection 和 selectionArgs 参数来约束,防止所有行都会受到影响

删除这条数据:

contentResolver.delete(uri,"column2 = ?",arrayOf("1))

接下来我们利用目前所学的知识,读取系统通讯录中的联系人信息

读取系统联系人

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/contactsView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

代码

class TestActivity : AppCompatActivity() {
   
    private val contactsList = ArrayList<String>()
    private lateinit var adapter: ArrayAdapter<String>

    override fun onCreate(savedInstanceState: Bundle?) {
   
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList)
        contactsView.adapter = adapter
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_CONTACTS
            ) != PackageManager.PERMISSION_GRANTED
        ) {
   
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS), 1)
        } else {
   
            readContacts()
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
   
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
   
            1 -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
   
                readContacts()
            } else {
   
                Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun readContacts() {
   
        contentResolver.query(
            ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null
        )?.apply {
   
            while (moveToNext()) {
   
                //获取联系人姓名
                val displayName =
                    getString(getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
                //获取联系人手机号
                val number =
                    getString(getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
                contactsList.add(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值