前言:人外有人,天外有天。不得不佩服那些能写出高效率代码的大神,跟他们的代码逻辑一比较,真的是......唉,不忍直视,但是千万不要灰心丧气,我们这些小喽罗要做的就是理解他们的思路并实时做总结,最后吸收为自己的东西,这篇是关于使用ContentReslover查询数据的,真的算是一种进阶吧,我边上代码边跟大家解释吧~
我们都是知道数据库里面有很多的表,比如sms的数据库,有contact的数据库等等很多,有时候你要做的是查询第一张表的结果要作为查询第二张表的条件,比如:查询短信黑名单时,你可以获取到号码,短信内容,ID,日期之类的,但是要获取号码对应的联系人姓名时,你就得根据号码来查询联系人数据库了(有的小伙伴说,短信数据库不是有person字段么,有必要查询联系人表么?那么我可以负责人的告诉你,很有可能,person返回的是null,具体的原因可以上网查找),那么现在就跟着一步一步的看吧~
First Version
Cursor cur =context.getContentResolver().query(builder.build(), null, null, null, "date DESC");
if(cur != null){
try {
if(cur.moveToFirst()){
int index_id = cur.getColumnIndex(SMS_DB_ID);
int index_number = cur.getColumnIndex(SMS_DB_NUMBER);
int index_content = cur.getColumnIndex(SMS_DB_CONTENT);
int index_date = cur.getColumnIndex(SMS_DB_DATE);
int index_category = cur.getColumnIndex(SMS_DB_CATEGORY);
do {
smsItems.add(
new SmsItem(
cur.getInt(index_id),
cur.getString(index_number),
cur.getString(index_content),
cur.getLong(index_date),
cur.getInt(index_category)));
} while (cur.moveToNext());
以上就是我查询的短信数据库的一些信息,最终存放到smsItems这个列表当中,接下来,我要去根据smsItems中每一个数据号码去查询联系人表中的数据
String SMS_DATA = "data1 = ?";
StringBuilder contactsSelections = new StringBuilder();
String contactsSelectionArgs[] = new String[smsItems.size()];
for(int i = 0; i < smsItems.size();i++){
if(i == smsItems.size() -1){
contactsSelections.append(SMS_DATA);
}else{
contactsSelections.append(SMS_DATA + " OR ");
}
contactsSelectionArgs[i] = smsItems.get(i).getNumber();
}
以上是拼接字符串,用来查询联系人表中符合条件的语句,下面进行正式的查询了
ContentResolver smsResolver = context.getContentResolver();
Cursor contatcCursor = smsResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,contactsSelections.toString,contactsSelectionArgs,null.null);
if (contatcCursor.moveToFirst()) {
do{
name = contatcCursor.getString(contatcCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
number = contatcCursor.getString(contatcCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
for(int i = 0;i < smsItems.size();i++){
if (smsItems.get(i).getNumber().equals(contactNumber)) {
smsItems.get(i).setName(contactName);
}
}
} while(contatcCursor.moveToNext());}
contatcCursor.close();
}
然后将每一项的数据绑定并进行显示,对,这就是第一个版本,是不是感觉跟你的写法很像,正常,我第一次也是这么写的,现在我们进行修改
Second Version
这个版本修改的内容很少,因为大神粗略的看了一下,“你这个sql语句拼写的太长啦,你可以试试in这个关键字”,然后我二话不说,立马百度了sql in 的关键字,修改如下:
StringBuilder contactsSelections = new StringBuilder();
for(int i = 0; i < smsItems.size();i++){
if(i == smsItems.size() -1){
contactsSelections.append(smsItems.get(i).getNumber());
}else{
contactsSelections.append(smsItems.get(i).getNumber() + ",");
}
}
<span style="font-size:14px;"><strong>Cursor contatcCursor = smsResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.NUMBER +"("+contactsSelections+")",null, null);</strong></span>
果然,改了之后去除了一个字符串数组,正当我得意的把代码给大神看的时候,“恩,不错,是修改了,但是这个smsItems中会有重复的数据吧,在你进行绑定的时候,岂不是又要重新循环一次?这样不怎么效率啊,可以有更好的写法,可以考虑这个Map<KeyType, List<ValueType>>"我当时就傻了,我说这个结构我哪知道啊,只能硬着头皮琢磨了1天,还是没有整出来,最后还是虚心请教大神~
Third Version
首先得声明一个类
private static class Multimap<K,V> {
private HashMap<K,List<V>> store = new HashMap<K,List<V>>();
List<V> getAll(K key) {
List<V> values = store.get(key);
return values != null ? values : Collections.<V>emptyList();
}
void put(K key, V val) {
List<V> curVals = store.get(key);
if (curVals == null) {
curVals = new ArrayList<V>(3);
store.put(key, curVals);
}
curVals.add(val);
}
Set<K> getAllKey() {
return store.keySet();
}
}
看看这个代码结构,跟我这种小学生写的完全不是一个境界的嘛,这个先暂时不说,看下面如何使用这个~
Multimap<String, SmsItem> map = new Multimap<String, SmsItem>();
声明,其中将类型替换成自己学要的,不多说了
do {
SmsItem smsItem = new SmsItem(
cur.getInt(index_id),
cur.getString(index_number),
cur.getString(index_content),
cur.getLong(index_date),
cur.getInt(index_category));
smsItems.add(smsItem);
map.put(smsItem.getNumber(), smsItem);
}while(cur.moveToNext())
这个地方就是使用这个结构了,每个号码对应一个smsItem,如果有相同的号码,则把第二个smsItem中的所有信息放入到List中,这个都有实现的
再来看看,如何方便的拼接字符串吧~
String contactsSelections = null;
String[] phoneNumbers = map.getAllKey().toArray(new String[map.getAllKey().size()]);
contactsSelections = TextUtils.join(",", phoneNumbers);
就是这么短,还需要什么for循环,以后千万不要用for循环来拼接了,太low啦~
最后,我们看如何进行数据的绑定~
for(SmsItem s: map.getAll(number)){
s.setName(name);
}
是不是简单的不要不要的~主要还是看自己的理解以及动手实践,让我们一起进步吧~