使用ContentResolver无法进行distinct查询的解决方法

发布时间:2013-9-23 18:07    发布者:reggae
关键词: android
场景假定:一个联系人A有两个电话号码,分别是32111268和32111269。现在要对联系人的电话进行查询,以得到联系人的raw_contact_id。
(PS:^_^不错的Android开发交流群314230976,验证:eec,有兴趣的话可以加入进来一起讨论)
我们知道,在Android系统中,所有和联系人有关的数据,都存储在数据库 /data/data/com.android.providers.contacts/databases/contacts2.db里面的data数 据表中,因此,可以对该表进行查询以获得联系人的raw_contact_id。对于上面假定的情况,在data数据表中和联系人A有关的电话记录有两 条,大致如下:
… |A’s raw_contact_id| … … |32111268|… …
… |A’s raw_contact_id| … … |32111269|… …
很显然,这两个电话号码属于同一个联系人。现在假定我们要查询电话号码中包含“32111”的联系人,在sqlite命令行下可以这么写(假定按raw_contact_id排序):
1 SELECT DISTINCT raw_contact_id FROMdata WHERE mimetype_id = 5 ANDdata1 LIKE ‘2111%’ ORDER BY raw_contact_id;
这样就会得到唯一的
A’s raw_contact_id
但是如果写成:
1 SELECT raw_contact_id FROM data WHEREmimetype_id = 5 AND data1 LIKE‘2111%’ ORDER BY raw_contact_id;
得到的结果就是:
A’s raw_contact_id
A’s raw_contact_id
这显然不符合要求,因为对于同一个联系人的raw_contact_id,我们不希望在查询结果中出现两次。这就是为什么在前面一条sql语句中加上DISTINCT的原因。
在我们自己的Android应用中,要对contacts2.db进行访问进行访问, 只能通过ContentResolver对象,这是因为contacts2.db不属于我们自己的Android应用进程,因此,无法得到和 contacts2.db相关的SQLiteDatabase对象,进而无法调用SQLiteDatabase中的execSQL方法去执行上面的SQL 语句。同时,我们在使用ContentResolver对象对data数据表进行查询的时候,无法使用DISTINCT关键字!这就是说,如果一个联系人 有两个电话号码符合查询条件,那么该联系人的raw_contact_id就会在返回的Cursor对象中出现两次!下面的写法
01 ContentResolver resolver = context.getContentResolver();
02
03 Cursor cursor = resolver.query(Data.CONTENT_URI,
04
05 newString[]{Data.RAW_CONTACT_ID}, // 居然不支持distinct,如果在这里加上distinct将会出现错误!
06
07 Data.MIMETYPE + " = '"+ Phone.CONTENT_ITEM_TYPE + "' AND "+ Data.DATA1 + "LIKE '2111%' ",
08
09 null,
10
11 Data.RAW_CONTACT_ID);
和前面的
1 SELECT raw_contact_id FROM data WHEREmimetype_id = 5 AND data1 LIKE‘2111%’ ORDER BY raw_contact_id;
所得到的结果是一样的,会得到两个一模一样的A’ raw_contact_id,这显然不符合要求。
那么怎么办呢?我们知道Java中Set具有“A collection that contains no duplicate elements”,也就是说Set中的元素是唯一的,当调用add方法,往Set对象加入对象时,如果被加的对象已经在Set中存在,那么该对象将不会 被再次加入,以保证该对象在Set中的唯一性。为此,在上面代码的基础上,可以考虑使用实现了Set接口的HashSet。
  1. 1 HashSet hashSet = newHashSet();
  2. 2 // 用这种方式(Set)来保证唯一性
  3. 3
  4. 4 while(cursor.moveToNext()){
  5. 5 hashSet.add(cursor.getInt(0));
  6. 6 }
复制代码
这样一来,在hashSet中的A’s raw_contact_id就只有一个了,也就是说通过这种方式,变通地实现了distinct这个sql关键字的语义。
当然,这样会增加额外的处理时间,在一个有1200条记录,其中电话记录有710条的 data数据表中,上面的操作耗时30ms左右(ThinkPad T410, Android 模拟器环境下),对于普通的和联系人有关的应用而言,30ms的延迟算不了什么大事,因此这种变通的方式应该是可行的。
个人感觉,Android系统自带的联系人数据库及其ContentResolver 在很多时候都还算比较方面,但同样在很多情况下,也存在很明显的限制。对于喜欢自己写SQL语句的朋友而言,这种限制几乎是难以忍受的,比如无法通过 ContentResolver在contacts2.db中增加触发器(在sqlite命令行下是可以的,但这样对于要发布的和联系人有关的引用而言, 这样做是不合适的)等等。
进而言之,SQLite这个数据库短小精悍,包含的特点也算不少,总体说来相当不错,否则也就没有那么多公司采用它了。但同时也存在诸多不足:
1. 不支持存储过程;
2. 用C、C++可以比较方便地开发类似于存储函数之类的东西(就是在SQL语句中可以使用的那种函数),但用Java做同样的事情就相对很麻烦;
3. 在触发器内,不能显式地执行事务处理;
4. 无法预先制定触发器的触发执行顺序。这个从原理上来讲,稍微改动一下源码应该可以做到。
5. 在缺省情况下,插入数据的性能很糟糕。一秒钟插入数据记录的数量通常在20左右。用事务进行批量数据处理,可以大幅度提高insert的性能,但一个事务中批量的上限不能超过500(比如500次insert)。
而这些特点,在进行某些嵌入式应用开发的时候是非常有用的。因此在使用SQLite数据库的时候,要充分考虑到这些限制,或者能够找到可以变通解决问题的办法。

本文地址:https://www.eechina.com/thread-121269-1-1.html     【打印本页】

本站部分文章为转载或网友发布,目的在于传递和分享信息,并不代表本网赞同其观点和对其真实性负责;文章版权归原作者及原出处所有,如涉及作品内容、版权和其它问题,我们将根据著作权人的要求,第一时间更正或删除。
您需要登录后才可以发表评论 登录 | 立即注册

厂商推荐

  • Microchip视频专区
  • Dev Tool Bits——使用MPLAB® Discover浏览资源
  • Dev Tool Bits——使用条件软件断点宏来节省时间和空间
  • Dev Tool Bits——使用DVRT协议查看项目中的数据
  • Dev Tool Bits——使用MPLAB® Data Visualizer进行功率监视
  • 贸泽电子(Mouser)专区

相关视频

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
快速回复 返回顶部 返回列表