android contacts 源码分析,MTK Contacts代码分析

1.本文主要记录Contacts代码中和数据有关的类之间的关系,从中可以看到编辑Contact界面是如何与Contact数据联系在一起的。

RawContactDeltaList本质是ArrayList,用add来向里面添加RawContactDelta类型的对象。

在新建一个联系人的时候,先new一个RawContact,RawContact的构造函数如下:

c7c816f9a253?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

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方法如下:

c7c816f9a253?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

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

接下来,新建一个RawContactDelta对象,构造函数中传入的参数是上面的ValuesDelta对象。构造函数如下:

c7c816f9a253?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

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函数如下:

c7c816f9a253?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

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方法,函数调用如下:

c7c816f9a253?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

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)。可以看到,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表,用来联系人搜索用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值