Contacts应用入口类有2个:PeopleActivity.java和DialtactsActivity.java。PeopleActivity是联系人入口类,DialtactsActivity是拨号入口类,Contacts集成了联系人和拨号功能。Contacts主界面如图1所示:

图1

Contacts有三个标签页组成,最左边的是群组,中间的是所有联系人,右边是常用、收藏联系人。三个标签是ActionBar.Tab类对象,通过ActionBar的newTab()方法构建,主要代码在ActionBarAdapter.java中,添加三个标签代码是:

    addTab(TabState.GROUPS, R.drawable.ic_tab_groups, R.string.contactsGroupsLabel);addTab(TabState.ALL, R.drawable.ic_tab_all, R.string.contactsAllLabel);addTab(TabState.FAVORITES, R.drawable.ic_tab_starred, R.string.contactsFavoritesLabel);

addTab是一个自定义方法,代码如下:

    private void addTab(TabState tabState, int icon, int description) {final Tab tab = mActionBar.newTab();tab.setTag(tabState);tab.setTabListener(mTabListener);if (mShowTabsAsText) {tab.setText(description);} else {tab.setIcon(icon);tab.setContentDescription(description);}mActionBar.addTab(tab);}

第二个参数icon就是标签上的图标。

三个标签能够切换,必须实现ActionBar.TabListener监听器接口,必须实现onTabSelected方法:

     public abstract void onTabSelected (ActionBar.Tab tab, FragmentTransaction ft)

当选择某个标签时讲调用它。

每个标签都和一个Fragment对应,当选择某个标签时,对应的Fragment就会被调用显示。三个Fragment是:

     GroupBrowseListFragment.java(群组)DefaultContactBrowseListFragment.java(所有联系人)ContactTileListFragment.java(常用、收藏联系人)。

只要是Fragment,都有一个布局与其对应:

     group_browse_list_fragment.xmlcontact_list_content.xmlcontact_tile_list.xml

在入口类PeopleActivity.java中,采用getFragmentManager()方法获得FragmentManager实例便于管理Fragment,比如将Fragment从后台堆栈中弹出等。FragmentTransaction可以用来隐藏、添加、移除Fragment等操作,使用FragmentManager的beginTransaction方法,代码:

    FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction()

再用add方法将fragment生成的view添加到容器中,该容器嵌入在activity的布局中:

    transaction.add(R.id.tab_pager, mFavoritesFragment, FAVORITE_TAG);transaction.add(R.id.tab_pager, mAllFragment, ALL_TAG);transaction.add(R.id.tab_pager, mGroupsFragment, GROUPS_TAG);

要使得add、删除等方法生效,必须使用commit方法提交这些事务:

    transaction.commitAllowingStateLoss();

commitAllowingStateLoss和commit的区别是当退出activity时,防止提交后的状态丢失。

mAllFragment是DefaultContactBrowseListFragment的实例,是“所有联系人”的fragment,他是多继承类,其结构如下图所示:

从图看出,DefaultContactBrowseListFragment最终继承于Fragment,ContactListAdapter是与listview对应的自定义适配器,最终继承于CompositeCursorAdapter,而CompositeCursorAdapter实际上继承于BaseAdapter,系统采用了CompositeCursorAdapter方法的好处在于它已经实现了getView方法,并且采用了缓存技术,代码如下:

public View getView(int position, View convertView, ViewGroup parent) {ensureCacheValid();int start = 0;for (int i = 0; i < mSize; i++) {int end = start + mPartitions[i].count;if (position >= start && position < end) {int offset = position - start;if (mPartitions[i].hasHeader) {offset--;}View view;if (offset == -1) {view = getHeaderView(i, mPartitions[i].cursor, convertView, parent);} else {if (!mPartitions[i].cursor.moveToPosition(offset)) {throw new IllegalStateException("Couldn't move cursor to position "+ offset);}view = getView(i, mPartitions[i].cursor, offset, convertView, parent);}if (view == null) {throw new NullPointerException("View should not be null, partition: " + i+ " position: " + offset);}return view;}start = end;}throw new ArrayIndexOutOfBoundsException(position);}

它包含一个getView,具体实现是:

protected View getView(int partition, Cursor cursor, int position, View convertView,ViewGroup parent) {View view;if (convertView != null) {view = convertView;} else {view = newView(mContext, partition, cursor, position, parent);}bindView(view, partition, cursor, position);return view;}

它判断convertView是否为空,如果是,就用newView方法创建一个,如果不是,就采用已有的,这种方法无需每次都创建View对象,提高了效率。需要我们实现的只有2个:

bindView方法和newView方法。newView方法在ContactListAdapter中实现,bindView在DefaultContactListAdapter中实现。

newView是用来创建ListView的item布局的:

protected View newView(Context context, int partition, Cursor cursor, int position,ViewGroup parent) {ContactListItemView view = new ContactListItemView(context, null);view.setUnknownNameText(mUnknownNameText);view.setQuickContactEnabled(isQuickContactEnabled());view.setActivatedStateSupported(isSelectionVisible());return view;}

ContactListItemView继承ViewGroup,是每个item的布局,在这个布局中添加TextView显示联系人姓名,添加ImageView显示头像,再使用一个TextView显示姓名大写首字母。在ContactListItemView中,主要的实现方法有三个:

onMeasure, onLayout, dispatchDraw. onMeasure用来测量视图的大小尺寸,onLayout给视图布局,确定其位置,dispatchDraw起到分发的作用,正在画图的方法还是draw。

如果说newView是用来创建每个Item的布局,那么bindView是用来创建布局上每个子视图。bindVIew的代码如下:

protected void bindView(View itemView, int partition, Cursor cursor, int position) {final ContactListItemView view = (ContactListItemView)itemView;view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);if (isSelectionVisible()) {view.setActivated(isSelectedContact(partition, cursor));}bindSectionHeaderAndDivider(view, position, cursor);if (isQuickContactEnabled()) {bindQuickContact(view, partition, cursor, ContactQuery.CONTACT_PHOTO_ID,ContactQuery.CONTACT_ID, ContactQuery.CONTACT_LOOKUP_KEY);} else {bindPhoto(view, partition, cursor);}bindName(view, cursor);bindPresenceAndStatusMessage(view, cursor);if (isSearchMode()) {bindSearchSnippet(view, cursor);} else {view.setSnippet(null);}}

其中:bindSectionHeaderAndDivider是创建第一行首字母和首字母下面蓝色下划线以及首字母右边的计数器;bindName创建姓名TextView;

ContactEntryListFragment中实现了Fragment的onCreateView方法,该方法创建Fragment对应的视图,创建代码是:

mView = inflateView(inflater, container);

inflateView的实现代码:

protected View inflateView(LayoutInflater inflater, ViewGroup container) {return inflater.inflate(R.layout.contact_list_content, null);}

布局文件contact_list_content.xml即是所有联系人的根布局。创建完视图后,采用setAdapter将适配器添加到ListView中即可。

Android 4.0.3 联系人(通讯录)应用源码学习相关推荐

  1. Android 9.0系统恢复出场设置源码流程分析

    前言 作为Framework层的开发人员,如果我们想让系统恢复出厂设置,一般有一下三种方式: 1.在[系统设置页面]进入[恢复出厂设置页面],点击[恢复出厂设置]按钮. 2.直接通过adb发送恢复出厂 ...

  2. android 日历源码解析,Android 4.0日历(calendar)源码分析之概览

    Calendar 从4.0开始,谷歌android系统有了脱碳换骨的改变,相应的日历应用的代码架构也跟2.*完全不同.代码更规范,当然也更复杂,且涉及到了android开发的方方面面. 如果你熟悉了i ...

  3. 博通Broadcom SDK源码学习与开发3——Cable Modem Docsis3.0

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 1. Ch ...

  4. 博通Broadcom SDK源码学习与开发1——SDK源码探究与Cable Modem 系统编译

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 1. 博通 ...

  5. 博通Broadcom SDK源码学习与开发2——Bootloader功能和编译过程

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 0.写在前 ...

  6. 博通Broadcom SDK源码学习与开发10——Cable Modem IPv6地址

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 1. 相关 ...

  7. 博通Broadcom SDK源码学习与开发4——ECOS系统数据流

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 1. SD ...

  8. 博通Broadcom SDK源码学习与开发5——ECOS系统层剖析

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 1. Op ...

  9. 博通Broadcom SDK源码学习与开发12终结篇——TR069网管协议

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 1. TR ...

最新文章

  1. Maven:No goals have been specified for this build. You must specify a valid lifecycle phase
  2. 关于C#调用Excel的资源占用问题
  3. 为什么很多公司转型Go语言开发?Go语言能做什么
  4. 如何使用markdown编辑器?官方文档在此
  5. 【ArcGIS风暴】ArcGIS 10.2导入Excel数据X、Y坐标(经纬度、平面坐标),生成Shapefile点数据图层
  6. Python二级笔记(1)
  7. java old区_一次Jvm old过高的排查过程实战记录
  8. 迁移Exchange Server 2003
  9. Java 1.1字符串
  10. 关于Weex,你想了解的一切都在这里
  11. 解决Eclipse10配置Pydev不成功的问题
  12. KITTI数据集评估方法小结
  13. Java List retainAll方法使用注意事项
  14. 计算机无法启动printspooler,Win10安装打印机提示“Print Spooler无法启动”怎么办?...
  15. 高效实现统计分析(按日,月,周)查询功能
  16. 做产品,懂人性,触人心
  17. Android Studio连接驱动装不上应用程序无法正常启动(oxc000007b)
  18. 史记十表-卷十六-秦楚之际月表第四
  19. 咸鱼ZTMR实例—板载LED
  20. 删除计算机病毒怎么办,电脑软件客户端被误报病毒而删除了怎么办?

热门文章

  1. Android使用BACnet协议进行数据读写测试
  2. 物联网WiFi配网方式原来是这七种!
  3. 第三章 ArcGIS Pro创建 python 脚本工具(五)
  4. 计算机术语表达祝福,祝福新人的唯美句子
  5. i3 10105f怎么样 i310105f相当于i5什么档次 i310105f属于什么档次
  6. 音视频通信为什么要选择WebRTC?
  7. 站群系统服务器搭建,站群服务器 搭建
  8. 微信“空白昵称”来了,让你隐身起来!
  9. 【C语言项目】大奖赛程序
  10. 地图已知两点坐标画一条曲线