MTK Contacts代碼分析

1.本文主要記錄Contacts代碼中和數(shù)據(jù)有關(guān)的類之間的關(guān)系,從中可以看到編輯Contact界面是如何與Contact數(shù)據(jù)聯(lián)系在一起的腥椒。
RawContactDeltaList本質(zhì)是ArrayList,用add來向里面添加RawContactDelta類型的對(duì)象耻瑟。
在新建一個(gè)聯(lián)系人的時(shí)候庞溜,先new一個(gè)RawContact破讨,RawContact的構(gòu)造函數(shù)如下:

Screenshot from 2017-07-14 15:03:11.png

然后,會(huì)把新建聯(lián)系人選擇的Account信息加入到RawContact中尔苦,也就是在RawContact的mValues中put ACCOUNT_NAME涩馆、ACCOUNT_TYPE、DATA_SET信息允坚,如LocalPhoneAccount對(duì)應(yīng)的AccountWithDataSet為(“Phone”,“Local Phone Account”,null)
------------------到現(xiàn)在為止魂那,新建一個(gè)RawContact對(duì)象,并在里面防止Account信息---------------------
接下來調(diào)用ValuesDelta的fromAfter放稠项,傳入的參數(shù)是上面新建的RawContact對(duì)象的mValues變量涯雅,fromAfter方法如下:

Screenshot from 2017-07-14 15:12:17.png

接下來,新建一個(gè)RawContactDelta對(duì)象展运,構(gòu)造函數(shù)中傳入的參數(shù)是上面的ValuesDelta對(duì)象活逆。構(gòu)造函數(shù)如下:

Screenshot from 2017-07-14 15:14:38.png

接下來會(huì)調(diào)用,RawContactModifier.parseExtras(mContext, accountType, result, mIntentExtras)拗胜,其中的result就是上面新建的RawContactDelta蔗候,這個(gè)函數(shù)的第一步是調(diào)用parseStructuredNameExtra,而parseStructuredNameExtra函數(shù)第一步調(diào)用的是RawContactModifier.ensureKindExists(state, accountType, StructuredName.CONTENT_ITEM_TYPE);
參數(shù)state是RawContactDelta,accountType是LocalPhoneAccountType,這個(gè)函數(shù)的含義就是先判斷此種Account是否必須加入此種mimeType埂软,如果必須加入此種mimeType锈遥,那么就從RawContactDelta中去看看是否有這種Entry,注意RawContactDelta中有mValues和mEntries兩個(gè)不同的變量仰美,如果沒有的話就要調(diào)用insertChild了迷殿,這個(gè)函數(shù)就是新建ContentValues,然后put進(jìn)一些數(shù)據(jù)咖杂,然后調(diào)用ValuesDelta.fromAfter庆寺,然后將得到的ValuesDelta addEntry到RawContactDelta中,insertChild函數(shù)如下:

Screenshot from 2017-07-14 15:48:48.png

-------------------------到這里應(yīng)該可以看出來诉字,RawContactDelta中的mValues保存的是此次插入聯(lián)系人的Account信息懦尝,mEntries是這次插入聯(lián)系人對(duì)應(yīng)的AccountType應(yīng)該有的DataKind對(duì)應(yīng)的ValuesDelta--------------------------------------------------------------------------------------------------------------
之后會(huì)調(diào)用CompactRawContactsEditorView的setState方法,在這個(gè)setState方法里面會(huì)調(diào)用parseRawContactDeltas方法壤圃,通過閱讀代碼可以看到這個(gè)方法的作用是將RawContactDeltaList解析到Map<String,KindSectionDataList> mKindSectionDataMap中陵霉,一個(gè)mimetype對(duì)應(yīng)一個(gè)KindSectionDataList,KindSectionDataList保存的是KindSectionData對(duì)象伍绳,new KindSectionData需要accountType, dataKind, rawContactDelta踊挠。之后獲得mPrimaryNameKindSectionData,這個(gè)變量就是StructuredName這個(gè)mimetype對(duì)應(yīng)的KindSectionData和ValuesDelta對(duì)應(yīng)的Pair。然后會(huì)調(diào)用addKindSectionViews方法效床,這個(gè)方法就是根據(jù)解析到的mKindSectionDataMap數(shù)據(jù)來addView睹酌。以StructuredName為例,inflateKindSectionView方法inflate一個(gè)CompactKindSectionView,之后調(diào)用CompactKindSectionView的setState方法剩檀,傳入的兩個(gè)重要的參數(shù)就是StructuredName對(duì)應(yīng)的KindSectionData和ValuesDelta憋沿,然后調(diào)用addNameEditorViews創(chuàng)建Name的界面,這個(gè)addNameEditorViews方法會(huì)調(diào)用inflate一個(gè)StructuredNameEditorView沪猴,然后調(diào)用StructuredNameEditorView的setValues辐啄,把ValuesDelta和RawContactDelta傳進(jìn)去,StructuredNameEditorView extends TextFieldsEditorView在這個(gè)TextFieldsEditorView里面的setValues方法中运嗜,當(dāng)fieldView內(nèi)容發(fā)生變化時(shí)壶辜,會(huì)調(diào)用onFieldChanged方法,然后調(diào)用saveValue方法洗出,函數(shù)調(diào)用如下:

Screenshot from 2017-07-14 17:57:31.png

這個(gè)mEntry就是ValuesDelta士复,也就是說當(dāng)界面的內(nèi)容發(fā)生變化后,會(huì)使ValuesDelta也發(fā)生變化翩活。這個(gè)ValuesDelta也是在RawContactDelta中的mEntries里面。

2.在ContactSaveService的saveContact分析便贵。
最簡(jiǎn)單的新建一個(gè)聯(lián)系人菠镇,只有一個(gè)名字和號(hào)碼。RawContactDelta的buildDiffWrapper結(jié)果出來總共有四個(gè)operation承璃,分別是insert raw_contact,insert data,insert data,update raw_contact利耍。insert raw_contact屬于RawContactDelta的mValues數(shù)據(jù),里面有Account信息,insert data,insert data屬于RawContactDelta的mEntries盔粹,也就是編輯聯(lián)系人界面輸入的聯(lián)系人信息隘梨。但是,raw_contact和data是通過raw_contact_id關(guān)聯(lián)起來的舷嗡。由于在buildDiffWrapper的時(shí)候并沒有插入raw_contact表轴猎,那么插入data表的時(shí)候是如何保證raw_contact_id正確的呢?在RawContactDelta的buildDiffWrapper中进萄,解析完一個(gè)ValuesDelta后捻脖,會(huì)有這么一句代碼:bw.getBuilder().withValueBackReference(Data.RAW_CONTACT_ID, firstIndex);//firsetIndex為0.
四個(gè)operation是通過ContactsProvider2的applyBatch得到執(zhí)行的,按照順序先是insert raw_contact中鼠,于是調(diào)用到了operation的apply方法:results[i] = operation.apply(this, results, i)可婶。可以看到援雇,insert raw_contact后矛渴,會(huì)把results[0]賦值為new ContentProviderResult(newUri),這個(gè)newUri就是insert raw_contact返回的uri惫搏。之后insert data具温,執(zhí)行operation的apply方法的時(shí)候蚕涤,會(huì)先解析下mValuesBackReferences,其實(shí)就是把results[0]里的newUri找出id部分桂躏,然后把他放到ContentValues中钻趋,這樣就把raw_contact_id的正確值找到了,這就是operation和withValueBackReference的用途之一剂习。

3.聯(lián)系人搜索
還是以最簡(jiǎn)單的新建一個(gè)聯(lián)系人為例
插入聯(lián)系人會(huì)解析RawContactDelta蛮位,也就是用buildDiffWrapper方法來解析RawContactDelta的mValues和mEntries變量(都是ValuesDelta對(duì)象),buildDiffWrapper會(huì)先調(diào)用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一個(gè)ContentProviderOperation.Builder對(duì)象失仁,設(shè)置下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中们何。

會(huì)生成四個(gè)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;
}

}
這四個(gè)CPOWrapper:
第一個(gè)uri是content://com.android.contacts/raw_contacts,ContentValues是account_type=Local Phone Account aggregation_mode=2 account_name=Phone data_set=null------>調(diào)用ContactsProvider2的insertRawContact方法
第二個(gè)uri是content://com.android.contacts/data冤竹,ContentValues是raw_contact_id=398 data1=(884) 879-94 data2=2 mimetype=vnd.android.cursor.item/phone_v2------>調(diào)用ContactsProvider2的insertData方法
第三個(gè)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
第四個(gè)uri是content://com.android.contacts/raw_contacts,ContentValues是aggregation_mode=0------>調(diào)用ContactsProvider2的updateRawContact方法
insertData方法會(huì)去調(diào)用DataRowHandler的insert方法如DataRowHandlerForStructuredName的insert會(huì)插入到data表,然后由于我們是數(shù)據(jù)庫(kù)的transaction鹦蠕,當(dāng)所有的operation執(zhí)行完畢會(huì)調(diào)用onCommit方法冒签,然后會(huì)調(diào)用updateRawContactDisplayName方法,主要是根據(jù)data表的名字來更新raw_contact相關(guān)字段钟病,然后有onRawContactInsert方法主要是根據(jù)raw_contacts表中的內(nèi)容來新建一個(gè)contacts表記錄萧恕,最后是通過SearchIndexManager的updateIndexForRawContacts方法來更新search_index表,用來聯(lián)系人搜索用肠阱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末票唆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屹徘,更是在濱河造成了極大的恐慌走趋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缘回,死亡現(xiàn)場(chǎng)離奇詭異吆视,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)酥宴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門啦吧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拙寡,你說我怎么就攤上這事授滓。” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵般堆,是天一觀的道長(zhǎng)在孝。 經(jīng)常有香客問我,道長(zhǎng)淮摔,這世上最難降的妖魔是什么私沮? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮和橙,結(jié)果婚禮上仔燕,老公的妹妹穿的比我還像新娘。我一直安慰自己魔招,他們只是感情好晰搀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著办斑,像睡著了一般外恕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乡翅,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天鳞疲,我揣著相機(jī)與錄音,去河邊找鬼蠕蚜。 笑死建丧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的波势。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼橄维,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼尺铣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起争舞,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤凛忿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后竞川,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體店溢,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年委乌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了床牧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遭贸,死狀恐怖戈咳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤著蛙,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布删铃,位于F島的核電站,受9級(jí)特大地震影響踏堡,放射性物質(zhì)發(fā)生泄漏猎唁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一顷蟆、第九天 我趴在偏房一處隱蔽的房頂上張望诫隅。 院中可真熱鬧,春花似錦慕的、人聲如沸阎肝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)风题。三九已至,卻和暖如春嫉父,著一層夾襖步出監(jiān)牢的瞬間沛硅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工绕辖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摇肌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓仪际,卻偏偏與公主長(zhǎng)得像围小,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子树碱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容