BaseAdapter
当一个ListView设置了Adapter后,每次ListView刷新显示时会调用getCount()来确定需要显示的条目个数,然后重复调用getView(…)获取指定位置的View并绘制到指定位置上。
方便起见,一般列表中每个条目里包含的View在初始化时都会从布局文件得到(如LayoutInflater的inflate(…)方法)。
由于每个条目中的view一般都会包含多个view(如每个条目都是个包含两个ImageView的LinearLayout),然而条目的绘制更新需要设置每个子View的属性,此时多次的调用findViewById(…)会导致效率低下,于是常在第一次初始化列表的条目时就保存起来每个子View(View的setTag(Object)可以为一个View绑定一个数据,可以用此方法对每个条目对应的View容器绑定一个包含它的所有子View的对象,这就是所谓的ViewHolder)。
public class UnitAdapter extends BaseAdapter {
private LayoutInflater inflater;
..... //一般会保存上列表的所有条目的内容,此处省略
public UnitAdapter(Context c)
{
inflater=LayoutInflater.from(c);
}//构造函数根据需求创建,这里只为以后从布局文件得到View实例来说明问题
@Override
public int getCount() {
return count;//获得列表内条目数
}
@Override
public Object getItem(int position) {
return item;//获取指定位置条目
}
@Override
public long getItemId(int position) {
return position;//获取列表中指定位置的id,方便可直接返回position
}
static class ViewHolder
{
public View view1,view2....;
}//为保存每个子View的一个类
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//convertView: 此条目中保存的上一次绘制使用的view(容器)
ViewHolder holder;
if (convertView==null)
{
convertView=inflater.infalte(...);//条目首次绘制更新,直接对其从布局文件初始化
holder=new ViewHolder();
holder.view1=convertView.findViewById(...);//保存条目容器包含的子View
holder.view2=....;//同上操作,保存所有子View
/*对于一个从布局文件生成的View容器,其子View的id可认为是布局文件中指定的id(至少在findViewById中的使用可以使这样的),具体实现这里不做深究。*/
convertView.setTag(holder);//将子View的集合绑定在条目的View容器中,下次直接取用
}
else
{
holder=(ViewHolder)convertView.getTag();//当前条目以初始化过,直接取用子View集合进行操作
}
holder.view1......;//对条目中的子View详细操作,比如setText.....
return convertView;//返回更新过的条目View容器
/*
在这里并未直接对convertView做修改,而的确更新了列表。
其实对象本身是以指针(认为是引用也一样的)的形式来传递的,在我们的holder得到了View容器的所有子View后,可以认为是holder保存了所有子View的地址,对holder的修改就是对convertView的子View的修改了(就像c的数组吧)。
*/
}
}