美文网首页Android知识Android开发Android技术知识
Android通讯录实时监听的设计实现

Android通讯录实时监听的设计实现

作者: 木木00 | 来源:发表于2017-04-14 11:41 被阅读375次

    作者简介  原创微信公众号郭霖 WeChat ID: guolin_blog

    本篇是李政第三篇投稿,分享了实现监听通讯录联系人变化的过程,希望能够帮助到大家。

    李政的博客地址:

    http://blog.csdn.net/lz8362

    前言

    大家在使用微信的过程中,可以发现微信的通讯录可以和手机通讯录保持一致的增删变化,这点特性属于应用的易用性范畴,今天就来讲讲如何实现该功能。

    通讯录涉及到的表统一集中在contacts2.db中。其路径如下:

    /data/data/com.android.providers.contacts/databases/contacts2.db

    统一由 ContactsContract类 进行管理,我们经常调用的 Phone、Contacts、RawContacts 都是 ContactsContract 的子类,常见的读取操作一共涉及到三张表,数据路径为:

    三者关系如下:

    contacts表 中每一行是一个联系人,每个联系人对应着一个唯一的_id,每个联系人对应着raw_contacts表中一行或多行数据,通过 contact_id 确定对应关系。

    raw_contacts表 张每一行是某个联系人的联系信息,当有联系信息发生改变时,会修改其 version 字段。raw_contacts表 会通过把_id写入到 data表 的 raw_contact_id 字段中的方式,对应指定的详细信息,raw_contacts表 的每一行对应一行或多行data表中数据。

    data表 通过 raw_contact_id 确定其属于 raw_contacts表 哪一个联系人。每一行通过一个 mimetype_id 的字段来表示该行存储的是什么类型的数据,该字段引用了 mimetyps表,此表存储了常用的数据类型。

    通过比较,Row_contacts表 具有承上启下的作用,ContentObserver 是Android用来提供共享数据变化后操作的监听类,其抽象方法 onChange() 会在通讯录数据库发生变化后被回调。由 ContentResolver(Android用来对程序的共享数据进行增删改查)完成注册和管理。

    所以,通讯录的实时监听,可以通过 ContactObserver 对 raw_contacts表 进行监听来实现。

    监听通讯录需要声明的权限只需读取/写入联系人权限即可,如下:

    android.permission.READ_CONTACTS

    android.permission.WRITE_CONTACTS

    实施步骤

    一、在应用开始时,先对通讯录信息进行一次备份,这里用 ContentResoler 对 RawContacts.CONTENT_URI 进行查询时,只需读取 RawContacts._ID 和 RawContacts.VERSION 两个字段即可。将查询结果保存在Map中(暂且命名为baseMap)。查询语句如下:

    RawContacts.VERSION 标志着本行数据的更新状态,每当有本行数据有更新时,该标记会加1,可以用它来进行联系人变更的判断。

    重点说下 sort_key,sort_key 在这里是用来排序的,该字段本身是用来存放联系人首字母的,不管是在Android4.4之前还是之后,这个字段始终都是有值存在的,只是从首字母到联系人全拼音的区别,有的机型会是拼音加汉字的组合。

    可能会有同学说Android4.4之后的首字母是保存的 phonebook_label 这个字段上,很遗憾,当你真正去适配各种手机型号时,你会发现 phonebook_label 会有为空的情况,这种现象源于如今流行的ROM定制,你不能保证厂商在定制过程中会墨守成规,这种时候就看你的变通了。经过测试发现,对sort_key进行截取操作,获取其第一位字符,其效果和直接获取首字母有异曲同工之妙。

    二、开启监听服务,注册 ContentObserver,在其 onchange() 方法中执行查询操作。

    在 onCreate() 方法中执行注册操作,操作如下:

    其中 observer 即为 ContentObserver 的实现对象。

    RawContacts.CONTENT_URI 为本监听器监听的数据表,即为 raw_contacts表。由于 raw_contacts表 记录的数据是联系人的联系信息,包含通话记录、联系信息等,所以当用拨打电话、接听电话、增删修改联系人时,都会去更新 raw_contacts表。虽然理论上会导致对 RawContacts.CONTENT_URI 的监听被重复触发,但是不代表这种情况会一直发生。

    实际上,在使用应用的过程中,出现接听电话、拨打电话的概率是可以忽略的,而用户通讯录的联系人条目也不会出现万级这种情况,对于 raw_contacts表 偶尔出现的多次查询不会对应用本身产生影响。本身通讯录同步更新是一个易用性的体验,考虑太多,只会无从下手。

    三、当 onchange() 被触发时,首先保存一个通讯录变更标记 change 为 true,存储在 SharedPreferences 中,再执行查询 raw_contacts表 操作,操作同第一步。但是需要额外对 Cursor 得到的行数进行判断:

    后续执行查询操作,查询数据保存到Map中(暂且即为realizeMap)

    比较 baseMap 和 realizeMap 之间的区别,通过比较 RawContacts._ID,分为以下三种情况:

    (1)、baseMap中存在,realizeMap中不存在的,即为删除。

    (2)、baseMap中不存在,realizeMap中存在的,即为新增。

    (3)、baseMap中存在,realizeMap中也存在的,但是 RawContacts.VERSION 变了,即为修改。

    这里之所以要加上行数判断,因为在实际测试过程中,我发现,当手机在通话过程后,部分手机型号此时会禁止查询 raw_contacts表,从而导致监听服务获取不到数据,当应用重新回到前台时,才能正常查询。所以通过设置一个更新标记,当应用重新回到前台时,可以及时的通过标记再次执行更新操作。

    四、选取需要更新的 RawContacts._ID 获取其详细内容,查询 data表(不用考虑删除的,其ID已不存在),代码如下:

    Data表中记录着联系人的详细信息,使用选择语句

    Data.MIMETYPE + “=’” + Phone.CONTENT_ITEM_TYPE + “’”

    可以提出无关联系人选项,只保留手机联系人选项。Data.RAW_CONTENT_ID 与RawContacts._ID 是多对一的,连个选择语句配合使用才能确定最终需要的数据。

    监听通讯录变化整个流程就介绍完了。大家可以尝试动手试一下。

    文章原创作者GuoLin 书籍推荐

    郭林大神原创android 书籍:《第一行代码 android》

    淘宝链接:

    https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

    相关文章

      网友评论

        本文标题:Android通讯录实时监听的设计实现

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