从Android Contacts应用看CursorLoader——Contacts篇
还是以MTK为例,这里我们只分析数据获取,其实与环境关系,影响不大
那么,我们直接进入到联系人列表(DefaultContactBrowseListFragment)
源码位置
packages\apps\Contacts\src\com\android\contacts\list\DefaultContactBrowseListFragment
要说到联系人列表,我觉得有一个细节一定要先说清楚,因为大家一定会发现
android:id="@id/android:list"
很多Android初学者对于android:id="@id/android:list"很是好奇,为什么会有这样的id定义
这里先给大家解释一下什么是android:id="@+id"和android:id="@id"
android:id="@+id/"用户自定义
android:id="@id/"系统定义
既然说到是系统定义,那么我们就可以联想到ListActivity与ListFragment
就以ListActivity为例
LiveActivity本身继承了关于List操作的众多接口,我们可以方便的重写这些操作中需要的方法来实现自己需要的功能。
如果要用ListActivity,则 Activity的Layout文件中必须包括一个(只能一个)ListView,且ListView的id= "@id/android:list"。
如下代码,一个标准的ListActivity Layout文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00FF00"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<TextView id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF0000"
android:text="No data"/>
</LinearLayout>
请注意 ListView与TextView的id。前面说了,
1. ListView的Id为固定不变的,为"@id/android:list“,ListActivity会根据id自动查找ListView引用;在 Activity 中使用 setListAdapter(adapter); 时就默认设置到了这个list上。如果按一般控件的写法 <ListView android:id="@+id/myListView" …… />,则需要 findViewById 先得到控件对像,再调用对像的 setListAdapter(adapter);
2. 但如果当ListView中没有值而又想提示一句话时,那么用于指定显示提示信息的TextView的id 必须为”"@id/android:empty",提示的信息可以通过android:text进行指定。
在实际中,也可以这样写,如Android2.3中的call_detail.xml中:
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="outsideOverlay"
/>
<ScrollView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<TextView android:id="@+id/emptyText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/unknown"
android:textSize="20sp"
android:textColor="?android:attr/textColorSecondary"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:paddingTop="10dip"
android:gravity="center"
android:lineSpacingMultiplier="0.92"/>
</ScrollView>
这个写法更加实用了,可以通过在listview没有显示数据时可以用@+id/emptyText进行动态赋值,而不用像前一个例子中的将empty text固化到xml中。
说完了ListView,我们继续回归到正题上
所谓的联系人列表就是将我们要显示的数据放到ListView上,这就搞定了
此处 我们就告别DefaultContactBrowseListFragment,因为他做的事情很简单,就是最外层的UI 与我们的核心数据展示
其实关系不大,我们我们就直接进入到他的父类 public abstract class ontactBrowseListFragment extends
ContactEntryListFragment<ContactListAdapter>
protected void configureAdapter() {
......}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
.......
}
public void onLoaderReset(Loader<Cursor> loader) {
......}
虽然我们发现这些函数的出现,但是我们基本上都看得到
super.configureAdapter();的出现,所以,很明显,他们也只是做了上层的处理
那么,下一步。我们继续深入
public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter>
extends Fragment
在这里我们可以很欣慰的发现
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
onCreateView(inflater, container);
mAdapter = <span style="color:#ff0000;">createListAdapter();</span>
mListView.setAdapter(mAdapter);
........
}
protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
mView = inflateView(inflater, container);
mListView = (ListView)mView.findViewById(<span style="color:#ff0000;">android.R.id.list</span>);
......
View emptyView = mView.findViewById(<span style="color:#ff0000;">com.android.internal.R.id.empty</span>);
.....
}
很欣慰,我们找到了ListView与Adapter.到了这里是不是就感觉我们离联系人已经不远了
很好,那我们继续跟踪下去
protected abstract T createListAdapter();
原来他的实现在子类,那么我们先不管他
我们继续跟踪
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
.........
CursorLoader loader = createCursorLoader();
.......
mAdapter.configureLoader(loader, directoryId);
}
public CursorLoader createCursorLoader() {
return new CursorLoader(mContext, null, null, null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
......
startLoading();
....
}
public void onLoaderReset(Loader<Cursor> loader) {}
那么,我们现在要关注的就是我们的adapter了
protected ContactListAdapter createListAdapter() {
DefaultContactListAdapter adapter = new DefaultContactListAdapter(getContext());
.....
return adapter;
}
同样的 在DefaultContactListAdapter中
@Override
public void configureLoader(CursorLoader loader, long directoryId) {
}
protected void configureUri(CursorLoader loader, long directoryId, ContactListFilter filter) {
}
protected void configureSelection(
CursorLoader loader, long directoryId, ContactListFilter filter) {<span style="font-family: 'Microsoft YaHei'; ">}</span>
@Override
protected void bindView(View itemView, int partition, Cursor cursor, int position) {
final ContactListItemView view = (ContactListItemView)itemView;
......
}