合并联系人分析 --- 之二

Posted Achillisjack

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了合并联系人分析 --- 之二相关的知识,希望对你有一定的参考价值。

一键合并联系人的MergeContacts方法调用流程图如下,


MergeContacts方法如下,

mMergeTask = new QueryContactDetailAndMergeTask(this);
mMergeTask.execute(mSubGroupContactsIds);

构造QueryContactDetailAndMergeTask对象并调用execute方法,传入的参数mSubGroupContactsIds就是bindMergeContactId方法最后保存的所有分组联系人对应的id。

现在主要看对应的doInBackground方法,该方法主要逻辑如下,

1,初始化,再次获取subGroupRawContacts对象,并设置进度条,

Map<Long, ArrayList<Long>> subGroupRawContacts = params[0];
int count = subGroupRawContacts.size();
mProgressDialog.setMax(count);
ArrayList<Long> resultIds = new ArrayList<Long>();

2,遍历,分组进行合并,当全部删除完成或者点击了取消按钮就停止合并过程,

while (!isCancelled() && entryIter.hasNext() && !mCancle) 

合并过程界面如下,


调用MergeContactUtils 的getRawContactId方法进行一组的删除,

Map.Entry<Long, ArrayList<Long>> itemEntry = entryIter.next();
ArrayList<Long> itemList = itemEntry.getValue();
long id = mergeUtil.getRawContactId(itemList);
mCount ++; //删除个数,进行计数

删除完成之后,在UI线程中更新进度条,

((Activity) mContext).runOnUiThread(new Runnable() 
@Override
public void run() 
    if(mProgressDialog != null) 
         mProgressDialog.incrementProgressBy(1);    
•••  

getRawContactId方法主要逻辑如下,

1,利用分组的所有id信息构造id集合语句,保存在rawSet变量中,

StringBuilder IdSets = new StringBuilder(" in (");
for(int i = 0; i < rawContactIds.size() - 1; i++)
    IdSets.append("'" + rawContactIds.get(i) + "', ");

IdSets.append("'" + rawContactIds.get(rawContactIds.size() - 1) + "')");
String rawSet = IdSets.toString();

2,构造插入语句,利用operations保存,

ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
operations.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
.withValue(RawContacts.ACCOUNT_NAME, SimContactUtility.ACCOUNT_NAME_LOCAL).withValue(RawContacts.ACCOUNT_TYPE, SimContactUtility.ACCOUNT_TYPE_LOCAL)
.withValue(RawContacts.DATA_SET, null)
.withValue(RawContacts.AGGREGATION_MODE,RawContacts.AGGREGATION_MODE_DISABLED)
.build());

3,从分组的所有联系人中获取插入的name,number等对象,

当然也是通过查询,并且保存在operations中.

List<MergeContactFields> mergeObjects = createMergeFieldObject();
SQLiteDatabase db = getMergeDB();
for(MergeContactFields object : mergeObjects)
    object.mergeField(operations, rawSet, db);

closeMergeDB(db); //关闭数据库
clearObject(mergeObjects);//清理

4,利用operations,调用ContentResolver的applyBatch方法在Contacts2.db数据库中插入一个联系人,

ContentResolver resolver = mContext.getContentResolver();
ContentProviderResult[] results = null;
try 
   results = resolver.applyBatch(ContactsContract.AUTHORITY, operations);

5,插入成功后,利用rawSet从Contacts2.db数据库中删除该组对应的所有联系人。

mContext.getContentResolver().delete(RawContacts.CONTENT_URI,
 BaseColumns._ID + "" + rawSet, null);

比如,现在有5个联系人姓名相同,首先从Contacts2.db数据库查询这5个联系人的信息,获取姓名,号码以及图像等,构造一个联系人;然后将这个构造的联系人插入Contacts2.db数据库;最后从Contacts2.db数据库中删除这5个联系人。也就是相当于将5个姓名相同的联系人信息合并为一个联系人。

关键看构造联系人过程。

调用流程图如下,


1,调用createMergeFieldObject构造MergeContactUtils对象,

List<MergeContactFields> mergeObjects = new ArrayList<MergeContactFields>();
mergeObjects.add(new MergeName());
mergeObjects.add(new MergePhone());
mergeObjects.add(new MergeEmail());
•••

这些对象都是MergeContactUtils的内部类,并且都继承于MergeContactUtils,实现了mergeField方法。架构图如下,


2,调用getMergeDB方法获取数据库SQLiteDatabase对象,

MergeContactFields的getDB方法如下,

SQLiteDatabase db = null;
try 
       db = SQLiteDatabase.openDatabase(
"/data/data/com.android.providers.contacts/databases/contacts2.db", 
                    null, SQLiteDatabase.OPEN_READONLY);

就是contacts2.db数据库。

3,调用每一个MergeContactFields的mergeField方法,

for(MergeContactFields object : mergeObjects)
   object.mergeField(operations, rawSet, db);

注意,输入了operations参数, mergeField方法会对该参数进行进一步完善。

这些MergeContactFields的子类的mergeField方法几乎完全一样,都是选取第一个不为空的对象作为合并的对象。例如,获取图像对应的MergePhoto的mergeField方法主要逻辑如下,

1,利用rawSet进行查询,获取Cursor对象,

cursor = db.query(DATA_TABLE,  new String[]Data.DATA14, Data.DATA15,,
 COLUMNS_MIMETYPE_ID + " = '" + mimeType_Id + "' AND " + Data.RAW_CONTACT_ID 
+ rawSet, null, null, null, null, null);

2,对Cursor进行逐个遍历,如果图像不为空,就将对应的查询信息封装在operations中,然后跳出循环, 

while(cursor.moveToNext())
	data14 = cursor.getString(0);
	data15 = cursor.getBlob(1);
•••
if(data15 != null)
	   builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
	   builder.withValueBackReference(Photo.RAW_CONTACT_ID, 0);
	    builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
	     builder.withValue(Photo.PHOTO_FILE_ID, data14);
	     builder.withValue(Photo.PHOTO, data15);
	   operations.add(builder.build());
       break;
•••

因此,如果姓名相同的多个联系人有多余2个图像,则合并后的联系人的图像是第一个图像不会空的联系人。

最后调用ContentResolver的applyBatch方法在Contacts2.db数据库中插入一个联系人时,会利用operations变量。

当然,所有分组联系人合并完成后会更新界面。QueryContactDetailAndMergeTask的onPostExecute方法在此就不多论述了。

以上是关于合并联系人分析 --- 之二的主要内容,如果未能解决你的问题,请参考以下文章

想以编程方式在联系人中创建一个新组

从联系人中选择自动填充地址后,iOS UITextField 文本字段为空

合并联系人分析 --- 之一

BetaFlight模块设计之二十五:dispatch任务分析

Tornado 高并发源码分析之二---Tornado启动和请求处理流程

第二章(连续时间系统的时域分析之二)