2014-01-06 17:18:29

1. Phonebook中新建/编辑联系人的UI不是用xml文件写的,它是随着帐号类型的改变来加载不同的UI,比如SIM联系人,只有Name、Phone Number,如果是USIM,或许还有第二个号码、Email,但是本地联系人除了包含这些,还有Nickname,Website等,所以帐号如何定义以及UI如何加载就变得很复杂。

2. 帐号类型(以AdnAccountType SIM帐号为例)

继承关系:AdnAccountType.java --> BaseAccountType.java --> AccountType.java,在AccountType中有两个很重要的方法,如下:

 public ArrayList<DataKind> getSortedDataKinds() {
Collections.sort(mKinds, sWeightComparator);
return mKinds;
} public DataKind addKind(DataKind kind) throws DefinitionException {
kind.resourcePackageName = this.resourcePackageName;
this.mKinds.add(kind);
this.mMimeKinds.put(kind.mimeType, kind);
return kind;
}

addKind()方法添加kind到mKinds,getSortedDataKinds()取出来所有的kind,这两个方法的使用将在后面介绍。关于BaseAccountType,这个类是所有帐号类的父类,下面看AdnAccountType:

 public AdnAccountType(Context context, String resPackageName, String accountType) {
this.accountType = accountType;
//this.resPackageName = null;
this.syncAdapterPackageName = resPackageName; try {
addDataKindStructuredName(context);
addDataKindPhone(context); int simType = SimUtil.getIccType(context, AdnHelper.getSlotNumber(accountType));
if (simType == IccProviderConstant.USIM_TYPE
|| simType == IccProviderConstant.CSIM_TYPE) {
addDataKindEmail(context);
} mIsInitialized = true;
} catch (DefinitionException e) {
SpbLog.e(TAG, "Problem building account type", e);
}
} @Override
protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
R.string.nameLabelsGroup, -1, true, R.layout.structured_name_editor_view)); kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.nameLabelsGroup,
FLAGS_PERSON_NAME).setNeedFocus(true)); return kind;
} @Override
protected DataKind addDataKindPhone(Context context) throws DefinitionException {
DataKind kind = super.addDataKindPhone(context); kind.iconAltRes = R.drawable.ic_message_icon;
kind.actionHeader = new PhoneActionInflater();
kind.actionAltHeader = new PhoneActionAltInflater();
kind.actionBody = new SimpleInflater(Phone.NUMBER); kind.typeColumn = Phone.TYPE;
kind.typeList = Lists.newArrayList();
kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE)); kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE)); return kind;
}

可以看到,SIM卡帐号添加了Name和Phone number两种数据的UI,这符合SIM联系人只能添加名称和号码的规则,如果SIM卡是USIM或者CSIM,那么还可以添加Email信息,看if判断语句就知道了。在addDataKindStructuredName()方法里面,调用了前面介绍的addKind()方法,将一个DataKind对象添加进去,同时为这个DataKind对象的fieldList添加了EditField,这个fieldList包含的是要显示的View,其实就是phone number或者Email条目包含的子条目,这些item会在后面具体介绍。下面看一下较复杂的LocalAccountType:

 public LocalAccountType(Context context, String resPackageName) {
this.accountType = SpbIntents.ACCOUNT_TYPE;
this.resourcePackageName = null;
this.syncAdapterPackageName = resPackageName; try {
addDataKindStructuredName(context);
addDataKindNickname(context);
addDataKindPhone(context);
addDataKindEmail(context);
addDataKindStructuredPostal(context);
addDataKindIm(context);
addDataKindOrganization(context);
addDataKindPhoto(context);
addDataKindNote(context);
addDataKindWebsite(context);
addDataKindEvent(context);
addDataKindSipAddress(context);
addDataKindGroupMembership(context); mIsInitialized = true;
} catch (DefinitionException e) {
SpbLog.e(TAG, "Problem building account type", e);
}
} @Override
protected DataKind addDataKindPhone(Context context) throws DefinitionException {
final DataKind kind = super.addDataKindPhone(context); kind.typeColumn = Phone.TYPE;
kind.typeList = Lists.newArrayList();
kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true));
kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true));
kind.typeList.add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true));
kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER));
kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true).setCustomColumn(
Phone.LABEL)); kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE)); return kind;
}

可以看到,本地帐号包含更多的信息,而且光Phone number就包含了好多类型,如HOME,MOBILE,FAX等。

addDataKindStructuredName添加的是姓名相关的UI,都包含在在kind.fieldList中,每一个EditField基本可以认为是一个EditTest,如图:

而addDataKindPhone添加的是PhoneNumber相关的UI,kind.fieldList只包含一个EditField,可以看见只有一个EditText,但是kind.typeList添加了很多东西,可以通过点击Type Spinner来看到,共八个,和代码一致,如下图:

3. 上面分析了一个帐号类型类包含的东西,包含了一些DataKind,而每一个DataKind又有kind.typeList,kind.fieldList以及其他的属性。所以一个DataKind代表一个类型的信息,如Name,Phone number,Email等,但是Name里面包含很多具体信息,如prefix,suffix,first name等,Phone number里面包含一个EditText,但是有很多种号码类型等等,这样构成了一个完整的帐号类,而在加载UI的时候,就是根据当前的帐号来添加帐号里面包含的UI。具体如何加载后面分析。

4. 上面的分析涉及到两个辅助类:DataKind和EditField,下面分别看一下这两个类:

 public final class DataKind {

     public String resourcePackageName;
public String mimeType;
public int titleRes;
public int iconAltRes;
public int iconAltDescriptionRes;
public int weight;
public boolean secondary;
public boolean editable;
public StringInflater actionHeader;
public StringInflater actionAltHeader;
public StringInflater actionBody;
public boolean actionBodySocial = false;
public String typeColumn;
public int typeOverallMax;
public List<EditType> typeList;
public List<EditField> fieldList;
public ContentValues defaultValues;
public final int editorLayoutResourceId;
public SimpleDateFormat dateFormatWithoutYear;
public SimpleDateFormat dateFormatWithYear; public int maxLinesForDisplay; public DataKind() {
editorLayoutResourceId = R.layout.text_fields_editor_view;
maxLinesForDisplay = 1;
} public DataKind(String mimeType, int titleRes, int weight, boolean editable,
int editorLayoutResourceId) {
this.mimeType = mimeType;
this.titleRes = titleRes;
this.weight = weight;
this.editable = editable;
this.typeOverallMax = -1;
this.editorLayoutResourceId = editorLayoutResourceId;
maxLinesForDisplay = 1;
}
}

由上可见,DataKind就是一个封装信息的类,只起到封装信息的作用。

 public static final class EditField {
public String column;
public int titleRes;
public int inputType;
public int minLines;
public boolean optional;
public boolean shortForm;
public boolean longForm;
public boolean needFocus = false;
public boolean editable = true; public InputFilter[] inputFilters; public EditField(String column, int titleRes) {
this.column = column;
this.titleRes = titleRes;
} public EditField(String column, int titleRes, int inputType) {
this(column, titleRes);
this.inputType = inputType;
} public EditField setOptional(boolean optional) {
this.optional = optional;
return this;
}
public EditField setShortForm(boolean shortForm) {
this.shortForm = shortForm;
return this;
} public EditField setLongForm(boolean longForm) {
this.longForm = longForm;
return this;
} public EditField setMinLines(int minLines) {
this.minLines = minLines;
return this;
} public boolean isMultiLine() {
return (inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
} public EditField setNeedFocus(boolean needFocus){
this.needFocus = needFocus;
return this;
}
public EditField setEditable(boolean editable) {
this.editable = editable;
return this;
}
}

EditField与DataKind类似,封装了一些信息,至于这些信息是如何被解析的,在真正加载UI的时候再分析。

Android Phonebook编写联系人UI加载及联系人保存流程(二)的更多相关文章

  1. Android Phonebook编写联系人UI加载及联系人保存流程(一)

    2014-01-06 17:05:11 将百度空间里的东西移过来. 本文适合ROM定制做Phonebook的童鞋看,其他人飘过即可- Phonebook添加/编辑联系人UI加载及保存联系人流程,是一系 ...

  2. Android Phonebook编写联系人UI加载及联系人保存流程(三)

    2014-01-07 09:54:13  将百度空间里的东西移过来. 本文从点击“添加联系人”Button开始,分析新建联系人页面UI是如何加载,以及新的联系人信息是如何保存的,借此,我们一探Phon ...

  3. Android Phonebook编写联系人UI加载及联系人保存流程(五)

    2014-01-07 10:46:30 将百度空间里的东西移过来. 在前面的文章中我们分析了UI的加载,其中提到了一个重要的对象:RawContactDeltaList mState,我前面说过这个对 ...

  4. Android Phonebook编写联系人UI加载及联系人保存流程(四)

    2014-01-07 10:23:22 将百度空间里的东西移过来. 5. KindSectionView KindSectionView是何方神圣呢?它又是怎么怎么和一个DataKind,以及一个Ra ...

  5. Android Phonebook编写联系人UI加载及联系人保存流程(六)

    2014-01-07 11:18:08 将百度空间里的东西移过来. 1. Save contact 我们前面已经写了四篇文章,做了大量的铺垫,总算到了这一步,见证奇迹的时刻终于到了. 用户添加了所有需 ...

  6. Android ViewPager Fragment使用懒加载提升性能

     Android ViewPager Fragment使用懒加载提升性能 Fragment在如今的Android开发中越来越普遍,但是当ViewPager结合Fragment时候,由于Androi ...

  7. Android三种基本的加载网络图片方式(转)

    Android三种基本的加载网络图片方式,包括普通加载网络方式.用ImageLoader加载图片.用Volley加载图片. 1. [代码]普通加载网络方式 ? 1 2 3 4 5 6 7 8 9 10 ...

  8. Android 插件开发,做成动态加载

    为什么需要插件开发: 相信你对Android方法数不能超过65K的限制应该有所耳闻,随着应用程序功能不断的丰富,总有一天你会遇到一个异常: Conversion to Dalvik format fa ...

  9. Android开发中如何解决加载大图片时内存溢出的问题

    Android开发中如何解决加载大图片时内存溢出的问题    在Android开发过程中,我们经常会遇到加载的图片过大导致内存溢出的问题,其实类似这样的问题已经屡见不鲜了,下面将一些好的解决方案分享给 ...

随机推荐

  1. JavaSE复习_8 泛型程序设计

    今晚看了core Java的泛型部分,万万没有想到,当时看培训班视频入门的一带而过的泛型,有这样多的细节,整理了一下书里面提到的一些自认为的重点,方便以后观阅.由于是复习,一些基础知识跳过. △泛型类 ...

  2. Android开发面试经——3.常见Java基础笔试题

      Android开发(29)  版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http:/ ...

  3. 转自“脚本之家”!!JDBC之PreparedStatement类中预编译的综合应用解析

    JDK 文档:SQL 语句被预编译并存储在 PreparedStatement 对象中(PreparedStatement是存储在JDBC里的,初始化后,缓存到了JDBC里),然后可以使用此对象多次高 ...

  4. hiho1096_divided_product

    题目 给出两个正整数N和M, N <= 100, M <= 50, 可以将N分解成若干个不相等的正整数A1, A2... Ak的和,且A1, A2 ... Ak的乘积为M的倍数.即 N = ...

  5. 吐槽下近期的4G手机:

    吐槽下近期的4G手机: 1.iphone6和6p,分别是4.7和5.5吋屏,1810和2915毫安时不可拆卸电池,双核64位苹果A8处理器.电池容量太小,不经用,中度使用一天一充,而且不支持VOOC闪 ...

  6. 基于SourceTree 下的 Git Flow 模型

    基于SourceTree 下的 Git Flow 模型 1. sourceTree  是一个开源的git 图形管理工具,可下载mac版本,windows版本 2. Git Flow 是一套使用Git进 ...

  7. Laravel 实现定时任务

    运行命令schedule run 时laravel会去App\console\kernel.php文件中查找schedule方法,有没有要执行的定时命令 实现流程:首先可以自定义命令并注册命令(参考上 ...

  8. Web网页性能管理详解

    你遇到过性能很差的网页吗? 这种网页响应非常缓慢,占用大量的 CPU 和内存,浏览起来常常有卡顿,页面的动画效果也不流畅. 你会有什么反应?我猜想,大多数用户会关闭这个页面,改为访问其他网站.作为一个 ...

  9. 纯css3代码写无缝滚动效果

    主要用到css3中的动画 @keyframes, animation. 布局是外层一个div宽固定,然后overflow hidden 绝对定位,里面的ul 固定定位.通过对ul添加动画来实现效果.具 ...

  10. js中tagName和nodeName

    DOM里常见的三种节点类型(总共有12种,如docment):元素节点,属性节点以及文本节点,例如<h2 class="title">head</h2>,其 ...