5,查询关键代码解析
bindView ( )
ContactEntryListAdapter.java
疑惑1: 在bindView( )函数中,直接将itemView 直接转化为 ContactListItemView?
解答:在父类 CompositeCursorAdapter 的 getview 函数中,首先调用 newView() 然后才调用 bindView (都是抽象函数),而ContactEntryListAdapter实现newView()时创建ContactListItemView,所以在bindView函数中,可以将 itemView 直接转化为 ContactListItemView 。
疑惑2:为啥要这样实现,太麻烦了 (代码写的布局,不好维护也不好修改).
ContactListAdapter和PhoneNumberListAdapter都覆盖了newView()函数
onCreateLoader( )
ContactEntryListFragment.java implements LoaderCallbacks<Cursor>
在onCreateLoader中,根据条件新建不同的AsyncLoader,分别为
DirectoryListLoader和CursorLoader。并且 DefaultContactBrowseListFragment 覆盖了createCursorLoader方法新建了ProfileAndContactsLoader类,
所以MultiSelectContactsListFragment调用的是 ProfileAndContactsLoader但是 Dialer 的AllContactsFragment 和RegularSearchFragment还是调用 CursorLoader.
SmartDialSearchFragment.java覆盖了onCreateLoader函数,新建了SmartDialCursorLoader. 所以拨号盘匹配查询时调用SmartDialCursorLoader。
在onCreateLoader中,都调用了adapter.configureLoader(loader);
疑惑3:何时调用DirectoryListLoader?
configureLoader ( )
在ContactEntryListAdapter中, configureLoader是一抽象函数,分别在
PhoneNumberListAdapter(RegularSearchFragment)
DefaultContactListAdapter(AllContactsFragment,MultiSelectContactsListFragment)
SmartDialNumberListAdapter(SmartDialSearchFragment)
中实现。
第一,在DefaultContactListAdapter的onCreateLoader函数中,有两个判断,
首先, if (loader instanceof ProfileAndContactsLoader)
上文中分析,仅有MultiSelectContactsListFragment该语句为true。
其次, if (isSearchMode())
开始AllContactsFragment(只能加载联系人)以及MultiSelectContactsListFragment加载联系人时,为false。在MultiSelectContactsListFragment搜索联系人,当字符串不为空时才为true,为空时依然为false。所以MultiSelectContactsListFragment,
SmartDialSearchFragment以及RegularSearchFragment搜索联系人,当字符串为空时, MultiSelectContactsListFragment会显示所有联系人,而其他的不会显示任何联系人。那么,何时setSearchMode()呢,且听下回分解!
最后,查询时, String query = getQueryString();利用字符串设置不同loader的各种属性,为查询数据库做准备。比如loader.setUri(Contacts.CONTENT_URI);
第二, PhoneNumberListAdapter的onCreateLoader函数根据查询的字符串是否为空对CursorLoader设置不同的属性。
第三, SmartDialNumberListAdapter,最后专题讨论。
疑惑4: RegularSearchFragment和MultiSelectContactsListFragment查询的结果相同,为什么中间还有这么多的不一样,比如说属性的设置以及查询数据库的表好像也不一样?
setQueryString ( )
当进行查询时,字符串的改变最终会调用ContactEntryListFragment的
setQueryString函数,
setSearchMode(!TextUtils.isEmpty(mQueryString)mShowEmptyListForEmptyQuery);
用这个mShowEmptyListForEmptyQuery 来控制字符串为空时的区别,
Dialer中mShowEmptyListForEmptyQuery为true,当字符串为空时,查询的结果为空。Contacts 中mShowEmptyListForEmptyQuery 为false,当字符串为空时,显示全部的联系人。
到此,准备工作做完了,开始查询了。
loadInBackground ( )
ProfileAndContactsLoader是继承CursorLoader,所以实际的查询还是CursorLoader。
CursorLoader的loadInBackground实际是通过getContentResolver().query()来调用系统的ContentResolver来完成最后的加载/查询。查询完成后,调用不同Fragement的onLoadFinished来显示结果。
onLoadFinished ( )
ContactBrowseListFragment以及AllContactsFragment虽然调用了onLoadFinished
函数,但是基本看不出来有什么作用,最后都会调用到ContactEntryListFragment的onLoadFinished。首先有个判断,不知道是干啥的??
if (loaderId== DIRECTORY_LOADER_ID)
MultiSelectContactsListFragment第一个字符搜索时为true(loaderId),很奇怪的是
RegularSearchFragment会有loaderId =0,-1,1,2. 其他的两个是 loaderId =0
这是疑惑5
调用ContactEntryListAdapter 的changeDirectories函数将Cursor (利用
cursor.moveToNext())将查询到的数据写到的Partition中, 并更新显示。
如何将查询到的联系人通过listview准确显示出来?
CompositeCursorAdapter中包含getCount()函数, 可以得到数据(联系人)的条数。
在Ablistview通过mAdapter.getCount()调用就可以,在刷新view时,就可以一条不落的显示所有查询到的联系人。很久的疑惑终于明白了 /2016.04.14
6, SmartDialSearchFragment
前面三个类加载或者查询时,最后都是通过调用系统的CursorLoader来完成,拨号盘查询跟这个还有点不一样,首先SmartDialCursorLoader是自己写的,其次查询语言也是自己写的,因为是模糊查询,查询过程要复杂。
转换工作
在DialtactsActivity的onResume函数中
mDialerDatabaseHelper.startSmartDialUpdateThread();
将contacts2中的联系人的姓名,号码数据经过LatinSmartDialMap转换后写入dialer的smartdial_table表中,转换过程为数字号码不变,ABC字符转化为2等等。
loadInBackground
SmartDialCursorLoader中的loadInBackground函数首先调用
dialerDatabaseHelper.getLooseMatches得到查询结果,然后再将结果封装后返回。
DialerDatabaseHelper的getLooseMatches函数首先在smartdial_table表中查询出结果(查询语言不是调用数据库的),然后根据结果来筛选出最终结果。比如: Alex sume,Alexs lucy。在拨号盘输入27(as)可以都可以搜出,但是只会筛选出姓名中包含连续的as字符或者as为姓名的第一个字符的联系人,所以最终结果是 Alex sume。