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开发案例驱动教程》第六章