Contacts源码界面分析:
点击手机上的联系人图标,首先进入的启动的是PeopleActivity,他的布局文件时peopleactivity.xml,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
-->
<android.support.v4.view.ViewPager
android:id="@+id/tab_pager"
android:layout_height="match_parent"
android:layout_width="match_parent"
/>
<FrameLayout
android:id="@+id/contacts_unavailable_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<FrameLayout
android:id="@+id/contacts_unavailable_container"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</FrameLayout>
</FrameLayout>
继承关系如下:
public class PeopleActivity extends ContactsActivity
implements
View.OnCreateContextMenuListener,
ActionBarAdapter.Listener,
DialogManager.DialogShowingViewActivity,ImportExportDialogFragment.Listener,
ContactListFilterController.ContactListFilterListener,ProviderStatusListener {}
因为我们首先启动的是PeopleActivity,这个Activity首次被调用时候,要调用onCreat()方法,下面我们来认真分析一下这个方法:
@Override
protected void onCreate(Bundle savedState) {
if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start");
}
super.onCreate(savedState);
if (!processIntent(false)) {
finish();
return;
}
mContactListFilterController =ContactListFilterController.getInstance(this);
mContactListFilterController.checkFilterValidity(false);
mContactListFilterController.addListener(this);
mIsRecreatedInstance = (savedState != null);
createViewsAndFragments(savedState);
if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
}
}
它采用的是FramLayout布局,我们知道这种布局容器是重叠式的,最底层放的是ViewPager,布满了整个容器。中间层放的是FramLayout,这一层默认设置成不可见,是为了:当把这个容器设置成可见时,放在里面的所有fragment都立刻可见,当再设置成不可见时候,放在里面的fragment便都立刻不可见。
容器最顶层放置的是可见的FramLayout。里面就放置了包括点击通讯录直接进入我们能看到的privateDefaultContactBrowseListFragment mAllFragment;//所有联系人
private voidcreateViewsAndFragments(Bundle savedState):在这个方法中找到主界面setContentView(R.layout.people_activity);由于界面里放置了诸多fragment,所以需要fragmentmanager和transation:
finalFragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction transaction = fragmentManager.beginTransaction();用他们来管理各个fragment和实现他们之间的交换显示。在这里onCreat()函数中还进行了改电话本是运用在平板和手机上的判别:boolean isUsingTwoPanes =PhoneCapabilityTester.isUsingTwoPanes(this);在这里源程序创建了三个fragment:
mFavoritesFragment = (ContactTileListFragment)
fragmentManager.findFragmentByTag(FAVORITE_TAG);
mAllFragment =(DefaultContactBrowseListFragment)
fragmentManager.findFragmentByTag(ALL_TAG);
mGroupsFragment = (GroupBrowseListFragment)
fragmentManager.findFragmentByTag(GROUPS_TAG);
然后把这三个fragmentadd as children of theview pager。Page adapter只能改变fragment的可见性,而不能创建和销毁fragment。
findFragmentByTag 首先搜索manager's activity,其次搜索back stack,然后通过if (mFavoritesFragment == null)来判断对象是否已经加上标签,如果没有,则:
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);
下面就是为这三个fragment添加按键监听器:
mFavoritesFragment.setListener(mFavoritesFragmentListener);
//为联系人页面添加各种监听器
mAllFragment.setOnContactListActionListener(newContactBrowserActionListener());
mGroupsFragment.setListener(newGroupBrowserActionListener());
并为mAllFragment添加数据库数据变化的观察器
mAllFragment.setProviderStatusLoader(mProviderStatusLoader);
然后就是提交
transaction.commitAllowingStateLoss();
这里选择了可能丢失状态的情况下提交事务,不知道为什么?????
执行
fragmentManager.executePendingTransactions();
这里调用了另外一个线程来执行,不知道为什么?
参考资料:http://www.cnblogs.com/mybkn/articles/2455138.html
把mFavoritesFragment显示为点缀和队列的形式:mFavoritesFragment.setDisplayType(DisplayType.STREQUENT);
下面是来定义手机屏幕上面的actionbar了:
mActionBarAdapter = new ActionBarAdapter(this, this, getActionBar(),isUsingTwoPanes);
mActionBarAdapter.initialize(savedState, mRequest);
最后,是定义手机屏幕下面显示的menu了:
invalidateOptionsMenuIfNeeded();
到此,oncreatViewsAndFragments()介绍完毕!
联系人数据库分析:
重要的三张表:
1 contacts表
该表保存了多有现有联系人,一个联系人占有一行
ContactID 联系人次数 最后一次时间 是否有号码 是否被添加到收藏夹等
2 raw_contacts表
该表保存了所有创建过的联系人,一个联系人占有一行,有一列来标示是否被删除
两个ID RowContactID和ContactID,将1 2两张表联系起来
RowContactID ContactID 联系次数 最后一次联系时间 是否被添加到收藏夹
显示的名字 用于排序的汉语拼音等信息
3 mimetypes表
该表定义了所有的MimeTypeID,即联系人的各个字段的唯一标志
4 data表
该表保存了所有创建过的手机联系人的所有信息,每个字段占有一行,两个ID:MineTypeID RawContactID 从而将data表和raw_contacts表联系起来
对联系人的基本操作
读取联系人:
1 先读取contacts表,获取ContactsID
2 再在raw_contacts表中根据ContactsID获取RawContactsID
3 然后就可以在data表中根据RawContaID获取联系人的所有数据了
Contacts源码的search功能
1 它搜索的域名authorities是:
com.android.contacts
在这里可以看出:
Sycapter_phone.xml sycapter_sim.xml sycapter_unism.xml
android:searchSuggestAuthority="com.android.contacts"
android:searchSuggestIntentData="content://com.android.contacts/contacts/lookup"
lookup为要查询内容,有intent传输
用到搜索功能的activuty 需要在Intent-filter中指定android.intent.action.SEARCH,并在<meta-data>部分指定searchable configuration (指向res/xml/searchable.xml)
于是,我们查看了AndroidMenifest.xml,看到只要PeopleActivity注释了这个,于是说明,只要它利用到了搜索功能。