今天仔細研究了一下API Demo中的QuickContactsDemo樣本,感覺對ListActivity有了進一步的認識。下面結合官方文檔和自己的研究對ListActivity做個總結。
Screen Layout
ListActivity的預設布局由一個位於螢幕中心的全屏列表構成。如果你不想使用預設的布局,可以在onCreate()方法中通過setContentView()方法設定你自己的布局。
如果指定你自己定製的布局,你的布局中必須包含一個id為"@id/android:list"的ListView。 若你還指定了一個id為"@id/android:empty"的view,當ListView中沒有資料要顯示時,這個view就會被顯示,同時 ListView會被隱藏。
參考樣本:
1. 布局檔案,res/layout/main.xml。
Xml代碼
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="8dp" android:paddingRight="8dp"> < !-- 除了ListView和id為@id/android:empty的view之外,我們還可以任意添加view --> < TextView android:id="@+id/android:title" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="The following is a list:" /> < !-- id為@id/android:list的ListView為客戶化的list布局,如果沒有,則系統會調用預設的布局 --> < ListView android:id="@id/android:list" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00FF00" android:layout_weight="1" android:drawSelectorOnTop="false" /> < !-- 當ListView中沒有資料時,id為@id/android:empty的view就會顯示出來 --> < TextView android:id="@id/android:empty" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="#FF0000" android:text="No data" android:gravity="center_vertical|center_horizontal" /> < !-- 除了ListView和id為@id/android:empty的view之外,我們還可以任意添加view --> < TextView android:id="@+id/android:title" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="The following is a list:" /> < /LinearLayout>
2. Activity對應的Java檔案,ListActivityDemo.java。
Java代碼
package com.xeedroid;
import java.util.ArrayList;
import java.util.List;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
public class ListActivityDemo extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
List items = fillList();
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, items);
setListAdapter(adapter);
}
private List fillList() {
List items = new ArrayList();
items.add("星期一");
items.add("星期二");
items.add("星期三");
items.add("星期四");
items.add("星期五");
items.add("星期六");
items.add("星期日");
//items.clear();
return items;
}
}
3. 運行效果如下:
4. 放開java代碼中的"items.clear();"的注釋。使得ListView繫結資料源沒有資料。運行效果如下:
從運行結果上也可以看出綠色背景的ListView沒有顯示。
Row Layout
Android允許為列表中一個單獨的行指定布局。只要在ListAdapter對象中指定一個布局資源就可以了。
一個ListAdapter建構函式有一個參數來指定每一行的布局資源。此外,它還有另外兩個參數來指定哪一個資料域與行布局資源中的對象相關聯。這兩個參數一般是平行數組。
Android在R.layout類中提供了一些標準的布局資源。例如simple_list_item_1, simple_list_item_2, 和two_line_list_item。
參考樣本一(使用SimpleCursorAdapter):
1. 使用預設的布局。
2. Activity對應的Java代碼如下。
Java代碼
package com.xeedroid;
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract.Contacts;
import android.widget.ListAdapter;
import android.widget.SimpleCursorAdapter;
public class ListActivityDemo extends ListActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Cursor mCursor = this.getContentResolver().query(Contacts.CONTENT_URI,
null, null, null, null);
startManagingCursor(mCursor);
ListAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.two_line_list_item, mCursor, new String[] {
Contacts.DISPLAY_NAME, Contacts.TIMES_CONTACTED }, new int[] {
android.R.id.text1, android.R.id.text2 });
setListAdapter(adapter);
}
}
客戶化的行布局使用了系統的android.R.layout.two_line_list_item。
3. 運行效果如下:
參考樣本二(使用ResourceCursorAdapter):
1. 使用系統預設screen layout。
2. Activity對應的Java代碼QuickContactsDemo.java(帶注釋)如下:
Java代碼
package com.example.android.apis.app;
import com.example.android.apis.R;
import android.app.ListActivity;
import android.content.Context;
import android.database.CharArrayBuffer;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract.Contacts;
import android.view.View;
import android.view.ViewGroup;
import android.widget.QuickContactBadge;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;
public class QuickContactsDemo extends ListActivity {
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID, // 0
Contacts.DISPLAY_NAME, // 1
Contacts.STARRED, // 2
Contacts.TIMES_CONTACTED, // 3
Contacts.CONTACT_PRESENCE, // 4
Contacts.PHOTO_ID, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.HAS_PHONE_NUMBER, // 7
};
static final int SUMMARY_ID_COLUMN_INDEX = 0;
static final int SUMMARY_NAME_COLUMN_INDEX = 1;
static final int SUMMARY_STARRED_COLUMN_INDEX = 2;
static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 3;
static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 4;
static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 5;
static final int SUMMARY_LOOKUP_KEY = 6;
static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 7;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 尋找合格所有contact
String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ Contacts.DISPLAY_NAME + " != '' ))";
Cursor c =
getContentResolver().query(Contacts.CONTENT_URI, CONTACTS_SUMMARY_PROJECTION, select,
null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
// 將cursor交給Activity管理
startManagingCursor(c);
// 建立adapter,將客戶化的UI和要顯示的資料與adapter綁定
ContactListItemAdapter adapter = new ContactListItemAdapter(this, R.layout.quick_contacts, c);
// 將adapter和當前list activity綁定
setListAdapter(adapter);
}
/*
* ResourceCursorAdapter主要是將資料按照ListActivity的要求傳遞給它。它的祖宗類實現了List Adapter介面。
* 在對ListActivity介面進行渲染過程中,對於Cursor中每一條記錄都會依次調用newView和bindView方法來產生UI。
*/
private final class ContactListItemAdapter extends ResourceCursorAdapter {
public ContactListItemAdapter(Context context, int layout, Cursor c) {
super(context, layout, c);
}
// 將newView產生的view和當前cursor指定的資料繫結
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ContactListItemCache cache = (ContactListItemCache) view.getTag();
TextView nameView = cache.nameView;
QuickContactBadge photoView = cache.photoView;
// Set the name
cursor.copyStringToBuffer(SUMMARY_NAME_COLUMN_INDEX, cache.nameBuffer);
int size = cache.nameBuffer.sizeCopied;
cache.nameView.setText(cache.nameBuffer.data, 0, size);
final long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
final String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY);
cache.photoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
}
// 按照ContactListItemAdapter(Context context, int layout, Cursor c)中的layout產生view
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = super.newView(context, cursor, parent);
ContactListItemCache cache = new ContactListItemCache();
cache.nameView = (TextView) view.findViewById(R.id.name);
cache.photoView = (QuickContactBadge) view.findViewById(R.id.badge);
// Tag用於傳遞任意對象,將當前方法產生的view中的子view以參數的形式暴露,供bindView()調用
view.setTag(cache);
return view;
}
}
/*
* 自訂的資料結構,用於儲存newView()所產生的view中的元素(各個子view)
*/
final static class ContactListItemCache {
public TextView nameView;
public QuickContactBadge photoView;
public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
}
}
3. 行布局對應的資源檔,res/layout/quick_contacts.xml。
Xml代碼
< ?xml version="1.0" encoding="utf-8"?>
< RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:paddingLeft="0dip"
android:paddingRight="9dip"
android:layout_height= "wrap_content"
android:minHeight="48dip">
< QuickContactBadge
android:id="@+id/badge"
android:layout_marginLeft="2dip"
android:layout_marginRight="14dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="3dip"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_height= "wrap_content"
android:layout_width= "wrap_content"
android:src="@drawable/ic_contact_picture"
style="?android:attr/quickContactBadgeStyleWindowSmall" />
< TextView
android:id="@+id/name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:paddingLeft="2dip"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/badge"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
< /RelativeLayout>
ListActivity會根據row對應的layout檔案和資料逐漸渲染產生整個UI。
4. 運行效果如下:
Binding to Data
我們通過實現了ListAdapter的類的對象向ListView傳遞資料。
主要被使用的類有:SimpleAdapter,ArrayAdapter,SimpleCursorAdapter,ResourceCursorAdapter(用其子類)。
SimpleCursorAdapter,ResourceCursorAdapter(抽象類別)都是CursorAdapter的子類。在 CursorAdapter中有兩個方法:newView()和bindView()方法,newView方法用來建立一個 RowLayout,bindView方法用來向這個新的RowLayout綁定資料。需要使用ResourceCursorAdapter是因為有些資料不能用SimpleCursorAdapter來進行綁定。