android contacts 源码分析,MTK Contacts代码分析
1.本文主要記錄Contacts代碼中和數據有關的類之間的關系,從中可以看到編輯Contact界面是如何與Contact數據聯系在一起的。
RawContactDeltaList本質是ArrayList,用add來向里面添加RawContactDelta類型的對象。
在新建一個聯系人的時候,先new一個RawContact,RawContact的構造函數如下:
Screenshot from 2017-07-14 15:03:11.png
然后,會把新建聯系人選擇的Account信息加入到RawContact中,也就是在RawContact的mValues中put ACCOUNT_NAME、ACCOUNT_TYPE、DATA_SET信息,如LocalPhoneAccount對應的AccountWithDataSet為(“Phone”,“Local Phone Account”,null)
------------------到現在為止,新建一個RawContact對象,并在里面防止Account信息---------------------
接下來調用ValuesDelta的fromAfter放,傳入的參數是上面新建的RawContact對象的mValues變量,fromAfter方法如下:
Screenshot from 2017-07-14 15:12:17.png
接下來,新建一個RawContactDelta對象,構造函數中傳入的參數是上面的ValuesDelta對象。構造函數如下:
Screenshot from 2017-07-14 15:14:38.png
接下來會調用,RawContactModifier.parseExtras(mContext, accountType, result, mIntentExtras),其中的result就是上面新建的RawContactDelta,這個函數的第一步是調用parseStructuredNameExtra,而parseStructuredNameExtra函數第一步調用的是RawContactModifier.ensureKindExists(state, accountType, StructuredName.CONTENT_ITEM_TYPE);
參數state是RawContactDelta,accountType是LocalPhoneAccountType,這個函數的含義就是先判斷此種Account是否必須加入此種mimeType,如果必須加入此種mimeType,那么就從RawContactDelta中去看看是否有這種Entry,注意RawContactDelta中有mValues和mEntries兩個不同的變量,如果沒有的話就要調用insertChild了,這個函數就是新建ContentValues,然后put進一些數據,然后調用ValuesDelta.fromAfter,然后將得到的ValuesDelta addEntry到RawContactDelta中,insertChild函數如下:
Screenshot from 2017-07-14 15:48:48.png
-------------------------到這里應該可以看出來,RawContactDelta中的mValues保存的是此次插入聯系人的Account信息,mEntries是這次插入聯系人對應的AccountType應該有的DataKind對應的ValuesDelta--------------------------------------------------------------------------------------------------------------
之后會調用CompactRawContactsEditorView的setState方法,在這個setState方法里面會調用parseRawContactDeltas方法,通過閱讀代碼可以看到這個方法的作用是將RawContactDeltaList解析到Map mKindSectionDataMap中,一個mimetype對應一個KindSectionDataList,KindSectionDataList保存的是KindSectionData對象,new KindSectionData需要accountType, dataKind, rawContactDelta。之后獲得mPrimaryNameKindSectionData,這個變量就是StructuredName這個mimetype對應的KindSectionData和ValuesDelta對應的Pair。然后會調用addKindSectionViews方法,這個方法就是根據解析到的mKindSectionDataMap數據來addView。以StructuredName為例,inflateKindSectionView方法inflate一個CompactKindSectionView,之后調用CompactKindSectionView的setState方法,傳入的兩個重要的參數就是StructuredName對應的KindSectionData和ValuesDelta,然后調用addNameEditorViews創建Name的界面,這個addNameEditorViews方法會調用inflate一個StructuredNameEditorView,然后調用StructuredNameEditorView的setValues,把ValuesDelta和RawContactDelta傳進去,StructuredNameEditorView extends TextFieldsEditorView在這個TextFieldsEditorView里面的setValues方法中,當fieldView內容發生變化時,會調用onFieldChanged方法,然后調用saveValue方法,函數調用如下:
Screenshot from 2017-07-14 17:57:31.png
這個mEntry就是ValuesDelta,也就是說當界面的內容發生變化后,會使ValuesDelta也發生變化。這個ValuesDelta也是在RawContactDelta中的mEntries里面。
2.在ContactSaveService的saveContact分析。
最簡單的新建一個聯系人,只有一個名字和號碼。RawContactDelta的buildDiffWrapper結果出來總共有四個operation,分別是insert raw_contact,insert data,insert data,update raw_contact。insert raw_contact屬于RawContactDelta的mValues數據,里面有Account信息,insert data,insert data屬于RawContactDelta的mEntries,也就是編輯聯系人界面輸入的聯系人信息。但是,raw_contact和data是通過raw_contact_id關聯起來的。由于在buildDiffWrapper的時候并沒有插入raw_contact表,那么插入data表的時候是如何保證raw_contact_id正確的呢?在RawContactDelta的buildDiffWrapper中,解析完一個ValuesDelta后,會有這么一句代碼:bw.getBuilder().withValueBackReference(Data.RAW_CONTACT_ID, firstIndex);//firsetIndex為0.
四個operation是通過ContactsProvider2的applyBatch得到執行的,按照順序先是insert raw_contact,于是調用到了operation的apply方法:results[i] = operation.apply(this, results, i)??梢钥吹?#xff0c;insert raw_contact后,會把results[0]賦值為new ContentProviderResult(newUri),這個newUri就是insert raw_contact返回的uri。之后insert data,執行operation的apply方法的時候,會先解析下mValuesBackReferences,其實就是把results[0]里的newUri找出id部分,然后把他放到ContentValues中,這樣就把raw_contact_id的正確值找到了,這就是operation和withValueBackReference的用途之一。
3.聯系人搜索
還是以最簡單的新建一個聯系人為例
插入聯系人會解析RawContactDelta,也就是用buildDiffWrapper方法來解析RawContactDelta的mValues和mEntries變量(都是ValuesDelta對象),buildDiffWrapper會先調用buildDiffHelper,buildDiffHelper代碼如下:
private ContentProviderOperation.Builder buildDiffHelper(Uri targetUri) {
ContentProviderOperation.Builder builder = null;
if (isInsert()) {
// Changed values are "insert" back-referenced to Contact
mAfter.remove(mIdColumn);
builder = ContentProviderOperation.newInsert(targetUri);
builder.withValues(mAfter);
} else if (isDelete()) {
// When marked for deletion and "before" exists, then "delete"
builder = ContentProviderOperation.newDelete(targetUri);
builder.withSelection(mIdColumn + "=" + getId(), null);
} else if (isUpdate()) {
// When has changes and "before" exists, then "update"
builder = ContentProviderOperation.newUpdate(targetUri);
builder.withSelection(mIdColumn + "=" + getId(), null);
builder.withValues(mAfter);
}
return builder;
}
也就是new一個ContentProviderOperation.Builder對象,設置下Builder的mValues變量,buildDiffWrapper代碼如下:
public BuilderWrapper buildDiffWrapper(Uri targetUri) {
final ContentProviderOperation.Builder builder = buildDiffHelper(targetUri);
BuilderWrapper bw = null;
if (isInsert()) {
bw = new BuilderWrapper(builder, CompatUtils.TYPE_INSERT);
} else if (isDelete()) {
bw = new BuilderWrapper(builder, CompatUtils.TYPE_DELETE);
} else if (isUpdate()) {
bw = new BuilderWrapper(builder, CompatUtils.TYPE_UPDATE);
}
android.util.Log.i("sela","buildDiffWrapper targetUri="+targetUri
+",mimeType="+getMimetype()+",type="+((bw != null) ?bw.getType():null));
return bw;
}
也就是將前面new的builder封裝到BuilderWrapper中。
會生成四個CPOWrapper(即ContentProviderOperationWrapper),類如下:
public class CPOWrapper {
private ContentProviderOperation mOperation;
private int mType;
public CPOWrapper(ContentProviderOperation builder, int type) {
mOperation = builder;
mType = type;
}
public int getType() {
return mType;
}
public void setType(int type) {
this.mType = type;
}
public ContentProviderOperation getOperation() {
return mOperation;
}
public void setOperation(ContentProviderOperation operation) {
this.mOperation = operation;
}
}
這四個CPOWrapper:
第一個uri是content://com.android.contacts/raw_contacts,ContentValues是account_type=Local Phone Account aggregation_mode=2 account_name=Phone data_set=null------>調用ContactsProvider2的insertRawContact方法
第二個uri是content://com.android.contacts/data,ContentValues是raw_contact_id=398 data1=(884) 879-94 data2=2 mimetype=vnd.android.cursor.item/phone_v2------>調用ContactsProvider2的insertData方法
第三個uri是content://com.android.contacts/data,ContentValues是raw_contact_id=398 data5=悟 data1=孫悟空 data2=空 data6=null data4=null data3=孫 is_super_primary=1 mimetype=vnd.android.cursor.item/name
第四個uri是content://com.android.contacts/raw_contacts,ContentValues是aggregation_mode=0------>調用ContactsProvider2的updateRawContact方法
insertData方法會去調用DataRowHandler的insert方法如DataRowHandlerForStructuredName的insert會插入到data表,然后由于我們是數據庫的transaction,當所有的operation執行完畢會調用onCommit方法,然后會調用updateRawContactDisplayName方法,主要是根據data表的名字來更新raw_contact相關字段,然后有onRawContactInsert方法主要是根據raw_contacts表中的內容來新建一個contacts表記錄,最后是通過SearchIndexManager的updateIndexForRawContacts方法來更新search_index表,用來聯系人搜索用。
總結
以上是生活随笔為你收集整理的android contacts 源码分析,MTK Contacts代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图像处理URL
- 下一篇: Java开发自学教程!java从入门到精