Android核心基础-5.Android 数据存储与访问-4. ContentProvider 内容提供者-示例(操作联系人)

五、ContentProvider 内容提供者

续上一博文(Android核心基础-5.Android 数据存储与访问-4.ContentProvider 内容提供者-示例(监听短信)

前面讲了内容提供者ContentProvider和监听数据修改的ContentObserver

本讲续上一博文“短信的监听”讲解“操作联系人”

9.1 联系人

  1. 读联系人
    • 联系人数据是存储在com.android.providers.contacts应用的数据库中的, 该应用对外提供了ContentProvider
    • 下载原码可以得到Uri和path
    • 查询raw_contacts表得到手机中联系人的id, 用id作为条件查询data表即可得到联系人的数据
  2. 写联系人
    • 先向raw_contacts表写一个id
    • 再用这个id向data表写联系人数据
  3. 批量操作
    • ContentResolver.applyBatch()

9.2 探索路

我们启动模拟器->打开短信。发现log打印了一行如下:
07-26 15:21:47.882: I/ActivityManager(1007): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.contacts/.activities.PeopleActivity bnds=[64,417][128,481] u=0} from pid 1146

从日志中我们看到系统启动的联系人应用程序的包名是com.android.contacts
根据这个包名我们去系统目录下查找data/data/com.android.contacts
很遗憾的发现没有数据库文件,那么我们添加的联系人数据都储存在哪里呢?
据我们上一“监听短信”博文中的学习知识可以知道,其也是一个展示界面,数据存储在另一个程序中,其通过ContentProvider对数据进行操作。
数据存储的程序为:com.android.providers.contacts
找到其程序目录下的库contacts2
该库中有好多表,但是我们关心表就三个。其他表我们现阶段不探讨

9.3 contacts2库的表关系

raw_contacts我们值关心_id字段他会外键关联到data表
data 中的raw_contacts_id对应raw_contacts表中的_id

mimetypes表

_idmimetype
1vnd.android.cursor.item/email_v2
2vnd.android.cursor.item/im
3vnd.android.cursor.item/nickname
4vnd.android.cursor.item/organization
5vnd.android.cursor.item/phone_v2
6vnd.android.cursor.item/sip_address
7vnd.android.cursor.item/name
8vnd.android.cursor.item/postal-address_v2
9vnd.android.cursor.item/identity
10vnd.android.cursor.item/photo
11vnd.android.cursor.item/group_membership

分析:
我们根据raw_contacts表_id的数量就知道有多少联系人
根据该_id查询data表raw_contacts_id字段就获得了每个联系人的数据
再根据每条联系人数据的mimetype_id字段对应mimetypes表的关系,就知道每条数据对应的数据类型。

9.4 Uri的获取

我们找到他的源码;
到github搜索到地址:https://github.com/CyanogenMod/android_packages_providers_ContactsProvider
找到联系人源码。
清单文件:

<provider android:name="ContactsProvider2"
            android:authorities="contacts;com.android.contacts"//授权/主机名(前面那个是早版本的,我们使用后面的)
            android:label="@string/provider_label"//标签
            android:multiprocess="false"//是否允许多进程同时使用
            android:exported="true"//应用程序可以被其他应用使用
            android:readPermission="android.permission.READ_CONTACTS"//读权限
            android:writePermission="android.permission.WRITE_CONTACTS">//写权限
            <path-permission
                    android:pathPrefix="/search_suggest_query"
                    android:readPermission="android.permission.GLOBAL_SEARCH" />
            <path-permission
                    android:pathPrefix="/search_suggest_shortcut"//操作其子集路径的权限
                    android:readPermission="android.permission.GLOBAL_SEARCH" />
            <path-permission
                    android:pathPattern="/contacts/.*/photo"
                    android:readPermission="android.permission.GLOBAL_SEARCH" />
            <grant-uri-permission android:pathPattern=".*" />
        </provider>

9.5 读取联系人

清单文件中配置读取联系人权限:

< uses-permission android:name=”android.permission.READ_CONTACTS”/>

读取所有联系人

private Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts");
    private Uri dataUri = Uri.parse("content://com.android.contacts/data");

    public void testRead() {
        ContentResolver resolver = getContext().getContentResolver();

        // 先查raw_contacts表, 得到所有id(contact_id非null)
        Cursor rawContactsCursor = resolver.query(rawContactsUri, new String[] { "_id" }, null, null, null);
        while (rawContactsCursor.moveToNext()) {
            long id = rawContactsCursor.getLong(0);
            // 用id作为条件, 查询data表中的数据

            Cursor dataCursor = resolver.query(dataUri, new String[] { "mimetype", "data1" }, "raw_contact_id=?", new String[] { id + "" }, null);
            while (dataCursor.moveToNext()) {
                String mimetype = dataCursor.getString(0);
                String data = dataCursor.getString(1);
                System.out.println(mimetype + ": " + data);
            }
        }
    }

运行程序打印如下:
07-26 17:17:08.497: I/System.out(4748): vnd.android.cursor.item/phone_v2: 1 501-099-0415
07-26 17:17:08.497: I/System.out(4748): vnd.android.cursor.item/email_v2: 374452668@qq.com
07-26 17:17:08.497: I/System.out(4748): vnd.android.cursor.item/name: 李建
07-26 17:17:08.497: I/System.out(4748): vnd.android.cursor.item/phone_v2: 555-6
07-26 17:17:08.497: I/System.out(4748): vnd.android.cursor.item/name: 张三丰
07-26 17:17:08.497: I/System.out(4748): vnd.android.cursor.item/phone_v2: 555-8
07-26 17:17:08.497: I/System.out(4748): vnd.android.cursor.item/name: 猪八戒

9.6 写入联系人

清单文件中配置读取联系人权限:

< uses-permission android:name=”android.permission.WRITE_CONTACTS”/>

写入单条联系人

public void testWrite() {
        ContentResolver resolver = getContext().getContentResolver();
        ContentValues values = new ContentValues();

        // 先向raw_contacts表写一个id
        Uri resultUri = resolver.insert(rawContactsUri, values);
        long id = ContentUris.parseId(resultUri);

        // 用这个id作为data表的raw_contact_id, 再写3条数据
        values.put("raw_contact_id", id);
        values.put("mimetype", "vnd.android.cursor.item/name");
        values.put("data1", "刘德华");
        resolver.insert(dataUri, values);

        values.put("mimetype", "vnd.android.cursor.item/phone_v2");
        values.put("data1", "13012345678");
        resolver.insert(dataUri, values);

        values.put("mimetype", "vnd.android.cursor.item/email_v2");
        values.put("data1", "ldh@163.com");
        resolver.insert(dataUri, values);
    }

批量插入多条联系人
// Android系统给我们封装好了事务,要么全部成功,要么全部失败

public void testWriteBatch() throws Exception {
        ContentResolver resolver = getContext().getContentResolver();
        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();     // 创建集合, 用来装多个操作

        ContentProviderOperation operation1 = ContentProviderOperation.newInsert(rawContactsUri)        // 创建一个Insert操作的Builder
                .withValue("_id", null)     // 设置要插入列名和数据(列名为_id, 数据为null时自动生成)
                .build();                   // 生成插入操作对象
        ContentProviderOperation operation2 = ContentProviderOperation.newInsert(dataUri)
                .withValueBackReference("raw_contact_id", 0)                // 插入的数据是同组第1个操作的结果
                .withValue("mimetype", "vnd.android.cursor.item/name")
                .withValue("data1", "齐天大圣")
                .build();
        ContentProviderOperation operation3 = ContentProviderOperation.newInsert(dataUri)
                .withValueBackReference("raw_contact_id", 0)
                .withValue("mimetype", "vnd.android.cursor.item/phone_v2")
                .withValue("data1", "13187654321")
                .build();
        ContentProviderOperation operation4 = ContentProviderOperation.newInsert(dataUri)
                .withValueBackReference("raw_contact_id", 0)
                .withValue("mimetype", "vnd.android.cursor.item/email_v2")
                .withValue("data1", "qtds@163.com")
                .build();

        operations.add(operation1);
        operations.add(operation2);
        operations.add(operation3);
        operations.add(operation4);

        resolver.applyBatch("com.android.contacts", operations);    // 一次性执行集合中的多个操作
    }

示例源代码->百度网盘

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值