資料庫中同步SIM卡聯絡人
4.2 同步聯絡人
當重新插入SIM卡時, SimContactsService 的onCreate方法內的匿名Handler的handleMessage方法對應的處理如下,
case MSG_SIM_REFRESH: ••• if (mSimState[sub] == SimContactsConstants.SIM_STATE_READY || mSimState[sub] == SimContactsConstants.SIM_STATE_LOAD) { if (!isSimOperationInprocess[sub]) { handleSimOp(sub); } else { Log.d(TAG, "queue refresh sim op"); refreshQueue.put(sub, MSG_SIM_REFRESH); }
如果正在處理SIM卡,則將訊息進行入棧,等前面的處理完成了才接著處理。
handleSimOp方法呼叫流程圖如下,
handleSimOp方法邏輯如下,
1,將isSimOperationInprocess置為true,然後從資料庫中刪除SIM卡聯絡人,如果是正常的話,這一步驟在SIM卡撥出的時候就已經完成了。
isSimOperationInprocess[slotId] = true;
deleteDatabaseSimContacts(slotId);
2,呼叫querySimContacts方法進行插入操作,
querySimContacts(slotId);
querySimContacts方法主要邏輯如下,
1,根據單卡還是雙卡構造不同SIM卡資料庫的Uri物件,
Uri uri = null; if (!isMultiSimEnabled()) { uri = Uri.parse("content://icc/adn"); } else { int[] subId = SubscriptionManager.getSubId(slotId); if (slotId < TelephonyManager.getDefault().getPhoneCount() && null != subId) { uri = Uri.parse("content://icc/adn/subId/" + subId[0]); •••
2,呼叫QuerySimHandler的startQuery方法進行非同步查詢操作,
mQuerySimHandler[slotId].startQuery(QUERY_TOKEN, null, uri, null, null, null, null);
QuerySimHandler是SimContactsService的內部類,繼承AsyncQueryHandler,實現了onQueryComplete方法。
查詢完成之後,會回撥QuerySimHandler的onQueryComplete方法,該方法如下,
mSimCursor[mSlotId] = c; //儲存查詢的Cursor物件
addAllSimContactsIntoDatabase(mSlotId);
addAllSimContactsIntoDatabase方法如下,
ImportAllSimContactsThread thread = new ImportAllSimContactsThread(slotId);
thread.start();
構造並啟動子執行緒, ImportAllSimContactsThread是SimContactsService的內部類,繼承Thread,
run方法主要邏輯如下,
1,構造Account物件,
Account account = createSimAccountIfNotExist(mSlotId);
Account 實現了Parcelable介面,並且有2個變數,
public class Account implements Parcelable {
public final String name;
public final String type;
在雙卡雙待的機器中插入一張卡,構造的Account物件如下,
2,對SIM卡查詢出的每條聯絡人,呼叫actuallyImportOneSimContact方法插入到Contacts2.db資料庫的raw_contacts表單
final ContentResolver resolver = mContext.getContentResolver();
Log.d(TAG, "import contact to account: " + account);
mSimCursor[mSlotId].moveToPosition(-1);
while (mSimCursor[mSlotId].moveToNext()) {
actuallyImportOneSimContact(mSimCursor[mSlotId], resolver, account);
}
3,完成插入操作之後,
mSimCursor[mSlotId].close(); //關閉Cursor物件
mSimCursor[mSlotId] = null;
•••
isSimOperationInprocess[mSlotId] = false; //重置狀態
sendPendingSimRefreshUpdateMsg(mSlotId);
sendPendingSimRefreshUpdateMsg方法如下,
Bundle args = new Bundle();
args.putInt(PhoneConstants.SLOT_KEY, slotId);
Message msg = mServiceHandler.obtainMessage();
msg.what = refreshQueue.get(slotId);
msg.obj = args;
mServiceHandler.sendMessage(msg);
refreshQueue.put(slotId, null);
從refreshQueue中取出訊息,繼續執行,和SimContactsService 的onCreate方法內的匿名Handler的handleMessage方法的
refreshQueue.put(sub, MSG_SIM_REFRESH);
前後呼應。
actuallyImportOneSimContact方法主要邏輯如下,
1,從SIM卡查詢出聯絡人的資訊
final String name = cursor.getString(cursor.getColumnIndex(COLUMN_NAME_NAME));
final String phoneNumber = cursor.getString(cursor.getColumnIndex(COLUMN_NAME_NUMBER));
•••
2,將查詢出的資訊封裝在operationList的ArrayList中,
if (!TextUtils.isEmpty(name)) {
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(StructuredName.DISPLAY_NAME, name);
operationList.add(builder.build());
}
•••
3,最後呼叫ContentResolver的applyBatch方法插入到Contacts2.db資料庫中。
resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
SimContactsService的結構圖如下,
小結:
1,當撥出SIM卡刪除Contacts2.db資料庫的SIM卡聯絡人時,直接就刪除了,並沒有使用非同步操作。
2,插上SIM卡,往Contacts2.db資料庫同步聯絡人主要分為2個過程;
首先利用AsyncQueryHandler從SIM卡資料庫非同步查詢聯絡人;
然後單開執行緒利用ContentResolver的applyBatch方法逐條將SIM卡聯絡人插入到Contacts2.db資料庫中。