1. 程式人生 > >資料庫中同步SIM卡聯絡人

資料庫中同步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資料庫中。