使用Android系统提供的ContentResolver,没法进行distinct查询的wo...

场景假定:一个联系人A有两个电话号码,分别是32111268和32111269。如今要对联系人的电话进行查询,以获得联系人的raw_contact_id。

 

咱们知道,在Android系统中,全部和联系人有关的数据,都存储在数据库/data/data/com.android.providers.contacts/databases/contacts2.db里面的data数据表中,所以,能够对该表进行查询以得到联系人的raw_contact_id。对于上面假定的状况,在data数据表中和联系人A有关的电话记录有两条,大体以下: android

…  |A’s raw_contact_id| … … |32111268|… … sql

…  |A’s raw_contact_id| … … |32111269|… … 数据库

很显然,这两个电话号码属于同一个联系人。如今假定咱们要查询电话号码中包含“32111”的联系人,在sqlite命令行下能够这么写(假定按raw_contact_id排序): ide

SELECT DISTINCT raw_contact_id FROMdata WHERE mimetype_id = 5 AND data1 LIKE ‘%32111%’ ORDER BY raw_contact_id; 函数

这样就会获得惟一的 性能

A’s raw_contact_id spa

 

可是若是写成: 命令行

SELECT raw_contact_id FROM data WHEREmimetype_id = 5 AND data1 LIKE ‘%32111%’ ORDER BY raw_contact_id; sqlite

获得的结果就是: 对象

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对象中出现两次!下面的写法

ContentResolver resolver = context.getContentResolver();

Cursor cursor = resolver.query(Data.CONTENT_URI,

new String[]{Data.RAW_CONTACT_ID},    // 竟然不支持distinct,若是在这里加上distinct将会出现错误!

Data.MIMETYPE + " = '"+ Phone.CONTENT_ITEM_TYPE + "' AND " + Data.DATA1 + "LIKE '%32111%' ",

null,

Data.RAW_CONTACT_ID);

和前面的

SELECT raw_contact_id FROM data WHEREmimetype_id = 5 AND data1 LIKE ‘%32111%’ 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。

 

HashSet<Integer> hashSet = new HashSet<Integer>();    // 用这种方式(Set)来保证惟一性

while(cursor.moveToNext())

{

hashSet.add(cursor.getInt(0));

}

这样一来,在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数据库的时候,要充分考虑到这些限制,或者可以找到能够变通解决问题的办法。

相关文章
相关标签/搜索