Android 访问其他程序中的数据

ContentProvider 的用法一般有两种:

一种是使用现有的ContentProvider 读取和操作相应程序中的数据;

另一种是创建自己的ContentProvider ,给程序的数据提供外部访问接口。

ContentResolver的基本用法

对于每一个应用程序来说,如果想要访问ContentProvider 中共享的数据,就一定要借助 ContentResolver 类,可以通过Context 中的getContentResolver()方法获取该类的实例。

ContentResolver 中提供了一系列的方法用于对数据进行增删改查操作,其中insert() 方法用于添加数据,update()方法用于更新数据,delete()方法用于删除数据,query()方 法用于查询数据。

有没有似曾相识的感觉?没错,SQLiteDatabase 中也是使用这几个方法进 行增删改查操作的,只不过它们在方法参数上稍微有一些区别。

不同于SQLiteDatabase ,ContentResolver 中的增删改查方法都是不接收表名参数的,而是使用一个Uri参数代替,这个参数被称为内容URI。内容URI给ContentProvider 中的数据建立了唯一标识符,它主要由两部分组成:authority 和path 。

  • 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,我们还需要在字符串的头部加上协议声明。因此, 内容URI最标准的格式如下:

1
2
3
content://com.example.app.provider/table1
 
content://com.example.app.provider/table2

有没有发现,内容URI可以非常清楚地表达我们想要访问哪个程序中哪张表里的数据。也正是因此,ContentResolver 中的增删改查方法才都接收Uri对象作为参数。如果使用表名的话,系统将无法得知我们期望访问的是哪个应用程序里的表。 在得到了内容URI字符串之后,我们还需要将它解析成Uri对象才可以作为参数传入。解析的方 法也相当简单,代码如下所示:

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

只需要调用Uri.parse()方法,就可以将内容URI字符串解析成Uri对象了。

现在我们就可以使用这个Uri对象查询table1 表中的数据了,代码如下所示:

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

这些参数和SQLiteDatabase 中query()方法里的参数很像,但总体来说要简单一些,毕竟这是在访问其他程序中的数据,没必要构建过于复杂的查询语句。

query()方法的参数说明

查询完成后返回的仍然是一个Cursor对象,这时我们就可以将数据从Cursor对象中逐个读取出来了。读取的思路仍然是通过移动游标的位置遍历Cursor的所有行,然后取出每一行中相应列的数据,代码如下所示:

1
2
3
4
5
while (cursor.moveToNext()) {
 val column1 = cursor.getString(cursor.getColumnIndex("column1"))
 val column2 = cursor.getInt(cursor.getColumnIndex("column2"))
}
cursor.close()

向 table1 表中添加一条数据,代码如下所示:

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

将待添加的数据组装到ContentValues中,然后调用ContentResolver 的 insert()方法,将Uri和ContentValues作为参数传入即可。

更新这条新添加的数据,把column1的值清空,可以借助ContentResolver 的 update()方法实现,代码如下所示:

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

调用ContentResolver 的delete()方法将这条数据删除掉,代码如下所示:

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

读取系统联系人

修改activity_main.xml 中的代码,如下所示:

1
2
3
4
5
6
7
8
9
10
<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"></ListView>
</LinearLayout>

修改MainActivity 中的代码,如下所示:

修改 AndroidManifest.xml 中的代码,如下所示:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
 
    <uses-permission android:name="android.permission.READ_CONTACTS" />

创建自己的ContentProvider 

...

 

posted @   草木物语  阅读(253)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2022-01-19 欧几里得算法(又称辗转相除法)
2022-01-19 数字证书
2022-01-19 数字签名
2022-01-19 消息认证码
2022-01-19 迪菲-赫尔曼密钥交换
2022-01-19 混合加密
2022-01-19 公开密钥加密
点击右上角即可分享
微信分享提示