美文网首页
Android笔记——ContentProvider

Android笔记——ContentProvider

作者: 莫忘初心_倒霉熊 | 来源:发表于2022-02-18 14:23 被阅读0次

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

ContentProvider的用法一般有两种:

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

1.0ContentResolver的基本用法

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

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标准的格式如下:


内容URI标准的格式

在得到了内容URI字符串之后,我们还需要将它解析成Uri对象才可以作为参数传入。解析的方法也相当简单,代码如下所示:


解析成Uri对象

1.1查询数据

query()方法定义如下所示:


query()方法定义 query()方法说明

查询完成后返回的是一个Cursor对象,通过移动游标的位置遍历Cursor的所有行,然后取出每一行中相应列的数据,代码如下所示:


查询数据

1.2添加数据

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


添加数据

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

1.3更新数据

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


更新数据

使用了selection和selectionArgs参数来对想要更新的数据进行约束,以防止所有的行都会受影响。

1.4删除数据

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


删除数据

2.0使用现有的ContentProvider查询系统联系人

查询系统联系人
  1. ContactsContract.CommonDataKinds.Phone类提供了一个CONTENT_URI常量,而这个常量就是使用Uri.parse()方法解析出来的结果。
  2. 联系人姓名这一列对应的常量是ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
    联系人手机号这一列对应的常量是ContactsContract.CommonDataKinds.Phone.NUMBER
  3. 最后千万不要忘记将Cursor对象关闭。

修改AndroidManifest.xml中的代码,加入了android.permission.READ_CONTACTS权限,如下所示:


修改AndroidManifest.xml

READ_CONTACTS权限属于危险权限,需要调用运行时权限的处理逻辑,具体使用方法,请看Android笔记——运行时权限

3.0创建自己的ContentProvider

3.1创建ContentProvider的步骤

3.1.1步骤一

要实现跨程序共享数据的功能,可以通过新建一个类去继承ContentProvider的方式来实现。ContentProvider类中有6个抽象方法,在使用子类继承它的时候,需要将这6个方法全部重写。代码示例如下:


代码示例

(1) onCreate():初始化ContentProvider的时候调用。
通常会在这里完成对数据库的创建和升级等操作,返回true表示ContentProvider初始化成功,返回false则表示失败。
(2) query():从ContentProvider中查询数据。
uri参数用于确定查询哪张表
projection参数用于确定查询哪些列
selection和selectionArgs参数用于约束查询哪些行
sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回
(3) insert():向ContentProvider中添加一条数据。
uri参数用于确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URI。
(4) update():更新ContentProvider中已有的数据。
uri参数用于确定更新哪一张表中的数据,新数据保存在values参数中
selection和selectionArgs参数用于约束更新哪些行,受影响的行数将作为返回值返回。
(5) delete():从ContentProvider中删除数据。
uri参数用于确定删除哪一张表中的数据
selection和selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。
(6) getType():根据传入的内容URI返回相应的MIME类型。

3.1.2步骤二

一个标准的内容URI写法是:


com.example.app应用的table1表中的数据
com.example.app应用的table1表中id为1的数据。

内容URI的格式主要就只有以上两种:

  1. 以路径结尾表示期望访问该表中所有的数据,
  2. 以id结尾表示期望访问该表中拥有相应id的数据。
    可以使用通配符分别匹配这两种格式的内容URI,规则如下:
    ● *表示匹配任意长度的任意字符。
    ● #表示匹配任意长度的数字。


    匹配任意表的内容URI格式
    匹配table1表中任意一行数据

借助UriMatcher这个类可以实现匹配内容URI的功能。

  • UriMatcher中提供了一个addURI()方法,可以分别把authority、path和一个自定义代码传进去。
  • 当调用UriMatcher的match()方法时,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。

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


修改MyProvider代码

table1Dir表示访问table1表中的所有数据
table1Item表示访问table1表中的单条数据
table2Dir表示访问table2表中的所有数据
table2Item表示访问table2表中的单条数据

在MyProvider类实例化的时候创建UriMatcher的实例,调用addURI()方法,将期望匹配的内容URI格式传递进去。当query()方法被调用的时候,就会通过UriMatcher的match()方法对传入的Uri对象进行匹配,如果发现UriMatcher中某个内容URI格式成功匹配了该Uri对象,则会返回相应的自定义代码,然后就可以判断出调用方期望访问的到底是什么数据了。

insert()、update()、delete()这几个方法的实现是差不多的,它们都会携带uri这个参数,然后同样利用UriMatcher的match()方法判断出调用方期望访问的是哪张表,再对该表中的数据进行相应的操作就可以了。

3.1.3步骤三

getType()方法是所有的ContentProvider都必须提供的一个方法,用于获取Uri对象所对应的MIME类型。
一个内容URI所对应的MIME字符串主要由3部分组成,Android对这3个部分做了如下格式规定。

● 必须以vnd开头
● 如果内容URI以路径结尾,则后接android.cursor.dir/
如果内容URI以id结尾,则后接android.cursor.item/
● 最后接上vnd.<authority>.<path>

对于content://com.example.app.provider/table1这个内容URI,它所对应的MIME类型就可以写成:

MIME类型
对于content://com.example.app.provider/table1/1这个内容URI,它所对应的MIME类型就可以写成:
MIME类型

完善MyProvider中的getType()方法逻辑,代码如下所示:


getType()方法逻辑

一个完整的ContentProvider就创建完成了,现在任何一个应用程序都可以使用ContentResolver访问我们程序中的数据。

那么,如何才能保证隐私数据不会泄漏出去呢?
因为所有的增删改查操作都一定要匹配到相应的内容URI格式才能进行,而我们当然不可能向UriMatcher中添加隐私数据的URI,所以这部分数据根本无法被外部程序访问,安全问题也就不存在了。

3.2实现自定义跨程序数据共享

3.2.1数据提供方

代码如下:


ContentProvider定义 onCreate() query() insert() update() delete() getTyoe()

ContentProvider一定要在AndroidManifest.xml文件中注册才可以使用。


AndroidManifest.xml文件

<application>标签内出现了一个新的标签<provider>,使用它来对DatabaseProvider进行注册。

  • android:name属性指定了DatabaseProvider的类名
  • android:authorities属性指定了DatabaseProvider的authority
  • android:enabled属性表示是否启用这个ContentProvider
  • android:exported属性表示是否允许外部程序访问我们的ContentProviderl

3.2.2数据访问方

添加数据 查询数据 更新数据 删除数据

相关文章

网友评论

      本文标题:Android笔记——ContentProvider

      本文链接:https://www.haomeiwen.com/subject/lqkdlrtx.html