一键合并联系人的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方法在此就不多论述了。