2014-01-07 10:46:30 将百度空间里的东西移过来。
在前面的文章中我们分析了UI的加载,其中提到了一个重要的对象:RawContactDeltaList mState,我前面说过这个对象很重要,和联系人保存有关,现在就分析一下联系人到底是怎么保存的。
1. 千里追踪mState
ContactEditorFragment类 bindEditorsForNewContact()方法中创建了一个RawContactDelta对象insert,代码如下:
1 private void bindEditorsForNewContact(AccountWithDataSet newAccount, 2 final AccountType newAccountType, RawContactDelta oldState, 3 AccountType oldAccountType) { 4 5 final RawContact rawContact = new RawContact(mContext); 6 if (newAccount != null) { 7 rawContact.setAccount(newAccount); 8 } else { 9 rawContact.setAccountToLocalContact(); 10 } 11 12 RawContactDelta insert = new RawContactDelta( 13 ValuesDelta.fromAfter(rawContact.getValues())); 14 15 if (mState == null) { 16 // Create state if none exists yet 17 mState = RawContactDeltaList.fromSingle(insert); 18 } else { 19 // Add contact onto end of existing state 20 mState.add(insert); 21 } 22 }
mState是一个RawContactDeltaList对象,而insert是一个RawContactDelta,上面代码中mState.add(insert),接着看,在bindEditors()方法中:
1 RawContactDelta rawContactDelta = getFirstVisibleContact(); 2 if (rawContactDelta != null) { 3 editor = createContactEditorView(rawContactDelta); 4 } 5 6 private RawContactDelta getFirstVisibleContact() { 7 for (final RawContactDelta rawContactDelta : mState) { 8 if (!rawContactDelta.isVisible()) continue; 9 return rawContactDelta; 10 } 11 return null; 12 }
我们发现,createContactEditorView(rawContactDelta)中的rawContactDelta就是mState中的第一个对象,也就是前面创建的insert,那么insert究竟什么呢?
insert = (Uri=content://com.android.contacts/raw_contacts, Values={ IdColumn=_id, FromTemplate=false, data_set=null, _id=-2, account_name=Phone contacts, account_type=com.android.localcontacts, }, Entries={})
可以看到,此时的insert只不过是一个只包含account信息,Entries为空的RawContactDelta对象,这个对象被当作参数传给createContactEditorView(rawContactDelta)方法,该方法中有:
1 editor.setState(rawContactDelta, type, mViewIdGenerator, isEditingUserProfile());
我们前面分析过,editor是一个自定义的BaseRawContactEditorView,参数如下:
rawContactDelta:传进来的RawContactDelta对象;
type:账户类型,此处为LocalAccountType;
isEditingUserProfile():是否是要编辑“我自己”条目;
此时rawContactDelta对象进入BaseRawContactEditorView类,该类又调用了父类RawContactCommonEditorView的super.setState(state, type, vig, isProfile);该方法有一个重要的else语句块,前面分析过,如下:
1 else { 2 // Otherwise use generic section-based editors 3 if (kind.fieldList == null) continue; 4 final KindSectionView section = (KindSectionView)mInflater.inflate(R.layout.item_kind_section, mFields, false); 5 section.setEnabled(isEnabled()); 6 section.setState(kind, state, false, vig); 7 mFields.addView(section); 8 }
rawContactDelta又被当作参数传到KindSectionView, 通过代码section.setState(kind, state, false, vig);进入KindSectionView类,在rebuildFromState()方法中:
1 if (hasEntries) { 2 for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) { 3 // Skip entries that aren't visible 4 if (!entry.isVisible()) 5 continue; 6 if (isEmptyNoop(entry)) 7 continue; 8 9 createEditorView(entry); 10 } 11 }
可以看到,在这里mState.getMimeEntries(mKind.mimeType),根mKind.mimeType从mState中取出entry,然后把entry传到reateEditorView()方法中,有如下代码:
1 private View createEditorView(ValuesDelta entry) { 2 final View view; 3 try { 4 view = mInflater.inflate(mKind.editorLayoutResourceId, mEditors, false); 5 } catch (Exception e) { 6 } 7 8 view.setEnabled(isEnabled()); 9 10 if (view instanceof Editor) { 11 Editor editor = (Editor) view; 12 editor.setDeletable(true); 13 editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator); 14 editor.setEditorListener(this); 15 } 16 mEditors.addView(view); 17 return view; 18 }
发现rawContactDelta以及根据mimetype生成的entry,又被当作参数传送,通过editor.setValues()方法,前面分析过editor是TextFieldsEditorView,那么看它的setValue()方法:
1 int fieldCount = kind.fieldList.size(); 2 mFieldEditTexts = new EditText[fieldCount]; 3 for (int index = 0; index < fieldCount; index++) { 4 final EditField field = kind.fieldList.get(index); 5 final EditText fieldView = createFieldView(field.column); 6 ...
这个方法应该很熟悉了,就是根据kind中fieldlist加载EditText的那个方法,同时还给生成的EditText注册了一个TextChangedListener, 如下:
1 fieldView.addTextChangedListener(new TextWatcher() { 2 @Override 3 public void afterTextChanged(Editable s) { 4 // Trigger event for newly changed value 5 onFieldChanged(column, s.toString()); 6 } 7 });
至于传进来的rawContactDelta和entry对象,调用了父类的setValues()方法,并将它们分别赋给了LabeledEditorView的mState和mEntry对象。既然给EditText对象添加了TextChangedListener,那么我们可以想到,应该是EditText中的内容发生改变后触发设置的监听方法,看这个监听方法:
1 @Override 2 public void onFieldChanged(String column, 3 String value) { 4 if (!isFieldChanged(column, value)) { 5 return; 6 } 7 saveValue(column, value); 8 notifyEditorListener(); 9 }
onFieldChanged()方法是在LabeledEditorView类里,和mState,mEntry对象在同一个类,我们看他的saveValue()方法:
1 protected void saveValue(String column, String value) { 2 mEntry.put(column, value); 3 }
我们发现,最终把用户输入的信息放到了mEntry中,既然mEntry是从mState中生成的,那么这些值也就保存到mState,我们在saveValue()方法中打Log,如下:
1 protected void saveValue(String column, String value) { 2 Log.d("David", "column = " + column); 3 Log.d("David", "value = " + value); 4 mEntry.put(column, value); 5 Log.d("David", "mState = " + mState); 6 }
如上图,我只在Name里面输入了“D”,我们看log截图:
column就是BaseAccountType中“StructuredName.GIVEN_NAME”,data2和数据库中的field是对应的,关于数据库,以后再分析;
1 kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given, 2 FLAGS_PERSON_NAME).setNeedFocus(true));
value表示的是用户输入的值;
mState是从ContactEditorFragment中传进来的RawContactDelta对象,取自RawContactDeltaList mState,这个mState(ContactEditorFragment中的)对象非常重要,因为当用户保存联系人时,会用到它。截图中倒数第二行,mimetype=vnd.android.cursor.item/name, data2=D,也就是说,用户输入的联系人信息是保存在对应的mimetype,比如这个是Name,下面我同时输入姓名和号码,再看一下log:
其中我输入的Name=David,number=18611975588.
上面我们千里追mState,以及弄清楚了用户输入的数据是怎么组织的,只是因为当用户点击保存Button时,要用到这个对象,以及该对象包含的值。