【Android】使用自定义Adapter优化ListView、修改数据及控件内部布局

时间:2021-12-20 21:13:32

之前使用 SimpleAdapter去显示ListView,当item很多时,系统会对每一条进行创建,但显示的却每次只有几条,有很多无用的item占据了内存,使用继承于BaseAdapter的adapter,通过重写各种方法,可以很好的帮助我们进行List显示,同时,BaseAdapter也支持GridView和Spinner,可对其他内容起到作用。
同样,对于数据存储存储在private ArrayList<Map<String, String>> list;
MainActivity中的配置adapter和设置listView点击事件(这里不推荐使用这种方式,尽量将所有item事件响应放在adapter中)比较简单

MyAdapter adapter=new MyAdapter(this);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
*************
});

之后看最主要的Myadapter类

  private class MyAdapter extends BaseAdapter {
private LayoutInflater inflater;//LayoutInfalter对象用来导入布局

public MyAdapter(Context context) {
this.inflater = LayoutInflater.from(context);
}

@Override
public int getCount() { //返回list项目的个数,在实际中,一般都是数据库中得到的数据条数
return (list.size());
}

@Override
public Object getItem(int position) {
return(list.get(position));

}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView==null) { //判断convertView是否为null 一般在最初绘制ListView的时候都为null
//随着绘制占据完屏幕 之后再将ListView移动 convertView的值将不为null
//而是之前被绘制过的值
convertView =inflater.inflate(R.layout.list_items_layout,null); //list_items_layout为自定义的布局
holder=new ViewHolder();
holder.item_bt_delete=(Button)convertView.findViewById(R.id.list_items_bt_delete);
holder.item_tv_date=(TextView)convertView.findViewById(R.id.list_items_date);
holder.item_tv_detail=(TextView)convertView.findViewById(R.id.list_items_detail);
holder.item_tv_dbnumber=(TextView)convertView.findViewById(R.id.list_items_dbnumber);
holder.item_tv_number=(TextView)convertView.findViewById(R.id.list_items_number);
convertView.setTag(holder); //绑定holder
}else{
holder=(ViewHolder)convertView.getTag(); //若convertView不为null 则说明之前对其绑定过 只需要重新拿出来即可
}

//配置数据
holder.item_tv_detail.setText(list.get(position).get("detail").toString());
holder.item_tv_date.setText(list.get(position).get("date").toString());
holder.item_tv_dbnumber.setText(list.get(position).get("dbnumber").toString());

holder.item_bt_delete.setOnClickListener(new View.OnClickListener() { //添加item中按钮的响应事件
@Override
public void onClick(View v) {
int key=Integer.parseInt(list.get(position).get("dbnumber").toString());
mgr.delete(key);
display();
}
});
return convertView;

}

public final class ViewHolder{
public Button item_bt_delete;
public TextView item_tv_detail;
public TextView item_tv_date;
public TextView item_tv_dbnumber;
public TextView item_tv_number;
}

}

具体内容看代码中的注释
listView在开始绘制的时候,首先调用getCount()函数,根据他的返回值得到listView的长度之后调用getView()逐一绘制每一行。

convertView的动态重用机制,将屏幕外的convertView回收并重新分发给进入屏幕的item,始终保证只有屏幕能够容下的item数量进行分配。

使用ViewHolder来方便我们对于adapter中控件的管理,其中在获取其android.R.id值得时候,注意使用convertView.finViewById()

convertView的setTag()和getTag()可以看做是数据与convertView对象的绑定和获取,跟随绑定的数据一起变化。


注:若想根据外围事件改变item控件的内容或者属性(例如长按listview改变控件Visibility),由于convertView代表了ListView的一个选项,是一个View对象,我们直接用convertView.setOnLongClickListener()设置convertView的事件即可,还有尽可能的将所有对item的操作都放在adapter当中,方便代码的调用


Button控件会抢夺listView的焦点,注意在xml中修改其值为false
android:focusable="false"