listview是android中最為常用的清單類型控件,listview中的選擇項目中樣式很多有的是純文字的、有的還可以帶有圖檔。它的繼承關系如下:
java.lang.object
↳ android.view.view
↳ android.view.viewgroup
↳ android.widget.adapterview<t extends android.widget.adapter>
↳ android.widget.abslistview
↳ android.widget.listview
android.widget.listview繼承了android.view.viewgroup。
首先看一個純文字的listview例子,案例運作後會出現一個城市清單如圖6-8所示,選擇某個城市,彈出一個toast,關于toast的概念和使用會在下一節中介紹。

圖6-8 listview
程式代碼請參考代碼清單6-4:
【代碼清單6-4】 chapter6_3/src/com/work/listview_1_activity.java
public class listview_1_activity extends activity {
private listview listview;
@override
public void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.listview_activity);
listview = (listview)findviewbyid(r.id.listview01);
arrayadapter<string> adapter = new arrayadapter<string>(this,
android.r.layout.simple_list_item_1, mstrings);
listview.setadapter(adapter);
listview.setonitemclicklistener(new adapterview.onitemclicklistener() {
@override
public void onitemclick(adapterview<?> parent, view v, int pos,
long id) {
toast.maketext(listview_1_activity.this, mstrings[pos],
toast.length_short).show();
}
});
}
private string[] mstrings = {
"北京市", "天津市", "上海", "重慶", "烏魯木齊", …};
}
對于arrayadapter應該已經很熟悉了,其中的android.r.layout.simple_list_item_1是使用系統的布局樣式。android系統本身提供了很多的這樣的布局檔案,但是有的适合于listview控件,有的适合于spinner控件,有的适合于它的清單控件,這是使用時需要注意的。
在這種方式下,需要在布局檔案listview_activity.xml中添加listview控件:
<listview android:id="@+id/listview01" android:layout_width="wrap_content"
android:layout_height="wrap_content"></listview>
由于listview在android中是很常用的清單類型控件,隻要是有多條資訊需要顯示的時候都可以考慮使用listview展示出來,正是由于listview使用的普遍,是以android又提供了一個清單類型的activity——listactivity,來簡化listview開發。
通過繼承listactivity類而實作一個簡單的listview功能,而不要直接使用listview控件。同樣上面案例如果使用listactivity請參考代碼清單6-5的寫法:
【代碼清單6-5】 chapter6_3/src/com/work/listview_1.java
public class listview_1 extends listactivity {
/** called when the activity is first created. */
@override
setlistadapter(new arrayadapter<string>(this,
android.r.layout.simple_list_item_1, mstrings));
getlistview().setonitemclicklistener(new adapterview.onitemclicklistener() {
toast.maketext(listview_1.this, mstrings[pos],
檢視代碼不難發現這裡沒有使用布局檔案,那就意味着不需要使用r檔案來獲得控件,是以在程式中使用了getlistview()方法來獲得listview控件。處理listview的項目點選事件有兩種方法,一種是通過與listview對象設定setonitemclicklistener方式實作,代碼如下:
getlistview().setonitemclicklistener(new adapterview.onitemclicklistener() {
@override
});
另外一種是覆寫listactivity的onlistitemclick(listview l, view v, int position, long id)方法實作,代碼如下所示。
protected void onlistitemclick(listview l, view v, int position, long id) {
toast.maketext(listview_1.this, mstrings[position], toast.length_short)
.show();
再看一個自定義adapter的例子,這是一個帶有圖示的listview,程式運作結果如圖6-9所示。
圖6-9 自定義adapter
相關程式代碼請參考代碼清單6-6:
【代碼清單6-6】 chapter6_3/src/com/work/listviewicon_3.java
public class listviewicon_3 extends listactivity {
setlistadapter(new efficientadapter(this));
private static final string[] data = {
"北京市", "天津市", "上海", "重慶", "哈爾濱",
"石家莊", "秦皇島", "濟南", "青島", "南京",
"三亞", "昆明", "成都", "長沙", "武漢",
"九江", "香港", "澳門","蘭州","張家口" };
…
自定義的adapter是efficientadapter,efficientadapter的相關代碼請參考代碼清單6-7:
【代碼清單6-7】 chapter6_3/src/com/work/listviewicon_3.java
private static class efficientadapter extends baseadapter {
private layoutinflater minflater;
private bitmap micon0;
private bitmap micon1;
… …
public efficientadapter(context context) {
minflater = layoutinflater.from(context);
micon0 = bitmapfactory.decoderesource(context.getresources(), r.drawable.noicon);
micon1 = bitmapfactory.decoderesource(context.getresources(), r.drawable.beijing);
… …
}
public int getcount() {
return data.length;
}
public object getitem(int position) {
return data[position];
public long getitemid(int position) {
return position;
public view getview(int position, view convertview, viewgroup parent) {
viewholder holder;
if (convertview == null) {
convertview = minflater.inflate(r.layout.main, null);
holder = new viewholder();
holder.text = (textview) convertview.findviewbyid(r.id.textview);
holder.icon = (imageview) convertview.findviewbyid(r.id.icon);
convertview.settag(holder);
} else {
holder = (viewholder) convertview.gettag();
}
holder.text.settext(data[position]);
switch(position)
{
case 0:
holder.icon.setimagebitmap(micon1);
break;
case 1:
holder.icon.setimagebitmap(micon2);
…
default:
holder.icon.setimagebitmap(micon0);
return convertview;
static class viewholder {
textview text;
imageview icon;
編寫自定義adapter可以繼承baseadapter類,如果是資料庫使用可以繼承cursoradapter。在本例中繼承了baseadapter類,baseadapter是一個抽象類,必須在它的子類中實作下面的方法:
• int getcount() 傳回總資料源中總的記錄數;
• object getitem(int position) 根據選擇的項目的位置,獲得選擇的資料源中某個項目的資料;
• long getitemid(int position) 根據選擇的項目的位置;
• view getview(int position, view convertview, viewgroup parent) 獲得要展示的項目view對象。
這裡最為麻煩的方法就是getview(),getview()方法是listview的每個清單項目繪制在螢幕上時被調用。該方法其中的一個參數是convertview,在listview第一次顯示清單項目的時候,convertview是null值。當向上滑動螢幕時候,螢幕上面的清單項目退出螢幕,螢幕下面原來不可見的清單項目會進入螢幕,這個時候的convertview不是null值,下面代碼的處理對于提供listview控件提高性能是至關重要的。
if (convertview == null) {
convertview = minflater.inflate(r.layout.main, null);
holder = new viewholder();
holder.text = (textview) convertview
.findviewbyid(r.id.textview);
holder.icon = (imageview) convertview.findviewbyid(r.id.icon);
convertview.settag(holder);
} else {
holder = (viewholder) convertview.gettag();
隻有在convertview為null時才去執行個體化控件,建立convertview對象、holder對象,其中convertview對象是通過minflater.inflate(r.layout.main, null)方法,從一個main.xml布局檔案中加載并建立的。
而在convertview非null的時候不會執行個體化控件,否則每次都要執行個體化控件,當清單項目很多時,使用者反複滑動螢幕會有“卡”的感覺,不再流暢了。
viewholder類是将每一個項目中的控件封裝起來的類,可以在convertview 為null時候建立viewholder類的執行個體holder,然後通過convertview.settag(holder);把它放到convertview中,而在convertview非null時候,再通過convertview.gettag()過的一個viewholder類的執行個體,這樣在翻屏的時候就不會反複建立viewholder執行個體對象了,就本例而言隻是建立了9個viewholder執行個體。
出自《android開發案例驅動教程》第六章