ContentResolver基本用法

内容提供器两种用法,使用现有的内容提供器读取和操作数据或者创建自己的内容提供器给程序的数据提供外部访问接口。

一个应用程序通过内容提供器如果对齐数据提供了外部访问接口,其他程序都可以通过这些接口访问这些数据。Android中的电话簿、短信、媒体库等程序都提供了类似的访问接口。

基本用法

要访问内容提供器中共享的数据,就需要借助ContentResolver类,通过Context中的getContentResolver方法获取该类的实例。这个类提供了insert\update\delete\query用于添加、更新、删除和查询数据。和SQLiteDatabase那块比较相似,但也有不同。

各个方法不需要传递表名参数,需要用一个Uri参数——内容URI替代,内容URI由authority和path两个部分组成,为内容提供器中的数据提供了一个唯一标志符。authority用来区分不同的应用程序,一般采用程序包名的方式命名避免冲突,例如包名为com.example.app,那么对应的authority命名为com.example.app.provider。path来区分统一程序中的不同表,通常加载authority之后,比如在数据库里面两张表table1和table2,path命名为/table1和/table2,这样URL就变成com.example.app.provider/table1和com.example.app.provider/table2,而内容uri还需要在字符串头部加上协议声明content://。内容URI标准写法如下:

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

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

内容URI字符串可以清楚的表达出是哪个程序的哪张表,ContentResolver中的增删改查方法接收内容URI。需要把URI字符串解析成URI对象。调用Uri.parse()方法即可解析。

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

然后用这个Uri对象来查询table1表中的数据。

Cursor cursor = getContentResolver().query(
    uri,
    projection,
    selection,
    selectionArgs,
    sortOrder);

那几个参数的意义在树上P255页给出了。和SQLite里面那个query很相似。

查询完返回一个Cursor对象,将数据从Cursor对象逐个读取:

if(cursor != null){
    while(cursor.moveToNext()){
        String column1 = cursor.getString(cursor.getColunmIndex("colunm1"));
        int column2 = cursor.getInt(cursor.getColumnIndex("column2");
    }
    cursor.close();
}

这是查询,下面是添加:

ContentValues values = new ContentValues();
values.put("column1", "text");
valuse.put("column2", 1);
getContentResolver().insert(uri.values);

将数据组装到ContentValues中,然后调用getContentResolver获取ContentResolver实例,然后在调用insert方法,传入uri对象和ContentValues对象。

下面是更新:

ContentValues values = new ContentValues();
values.put("column1", "");
getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[]{"text","1"});

这里后面用了selection和selectionArgs约束了一下,是列1=text和列2=1的那一行数据去更新,避免了其他行受影响。

删除:

getContentResolver().delete(uri, "column2 = ?", new String[]{"1"});

下面从几个例子实际体会一下。

读取系统联系人

先是在模拟器上新建了三个联系人。

新建一个ContactsTest项目开始动手

我们的目的是把联系人和电话号码显示在ListView中来,所以先布局一个ListView:

跟在运行时权限那一节讲的比较类似的,读取联系人是危险权限。我们需要申请运行时权限,同时把读取动作封装在readContacts里面,注意我们这里传入query的Uri不是常规意义上的parse之后的Uri对象,而是ContactsContract.CommonDataKinds.Phone类帮助我们做好封装的CONTENT_URI,这是个常量,就是用Uri.parse()解析出来的,遍历的时候用cursor对象取的时候,将姓名和手机号取出,姓名列对应常量为ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME

号码列对应常量为

ContactsContract.CommonDataKinds.Phone.NUMBER,最终代码如下:

注意一下finnally里面那个close还有try最后那个刷新ListView的notifyDataSetChanged()方法。运行之后:

ALLOW之后显示那个ListView,Deny之后显示一个Toast,我们ALLOW一下:

这就是用内容提供器实现跨程序共享数据的一个实例(在这个Test程序和手机通讯录之间的数据共享)

编辑于 2018-07-20 03:21