在使用listview和recyclerview的过程中免不了要用到convertview和viewholder,所以理解他们的工作原理还是很有意义的。
首先来看listview的使用,如果要写一个最简单的BaseAdapter的话,那么getView中直接用LayoutInflater根据布局文件生成一个View,然后再获取这个view的子组件设置属性,返回这个view就可以了。但是这个开销显然是不可以接受的,每一次要显示一条列表项的时候都需要执行一次这个过程,根据布局文件生成view。
1.convertView:
convertView是一个作为缓存的view,通过使用这个缓存可以替换掉用Inflater加载组件这一步。
首先做一个实验:
public class MyAdapter extends BaseAdapter {
private List<String> list;
private Context context;
private LayoutInflater inflater;
public MyAdapter(Context context){
//this.list=list;
this.context=context;
inflater=((Activity)context).getLayoutInflater();
}
@Override
public int getCount() {
return 100;
}
@Override
public Object getItem(int position) {
return ""+position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null){
convertView=inflater.inflate(R.layout.item_la,null);
TextView tv=convertView.findViewById(R.id.tv);
tv.setText("序号:"+position);
}
return convertView;
}
}
可以看到,convertView为空的时候给他赋值显示position,不为空的时候直接返回显示。
通过效果图发现,前11个列表项(大于一页)正常显示为0到10,从第12个开始再次显示为0到10,随着我缓慢滑动,整个列表总体显示为0-10的循环。但是当我快速滑动时,显示出的一页数字完全乱了。
总结一下,前11个view显示的时候接收的convertView为空,所以要自己给他赋值,也就是装入缓存。11个以后的view接收到convertView就是前面11个一一对应创建的convertView,但是这个顺序快速滑动起来就乱了,所以不能简单认为convertView遵循一个mod11的规律。
2.ViewHolder:
直接看convertView和ViewHolder一起用:
/**书中详细解释该方法*/
@Override
public View getView(finalint position, View convertView, ViewGroup parent) {
ViewHolder holder;
//观察convertView随ListView滚动情况
Log.v("MyListViewBase", "getView " + position + " " + convertView);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item,null);
holder = new ViewHolder();
/**得到各个控件的对象*/
holder.title = (TextView) convertView.findViewById(R.id.ItemTitle);
holder.text = (TextView) convertView.findViewById(R.id.ItemText);
holder.bt = (Button) convertView.findViewById(R.id.ItemButton);
convertView.setTag(holder);//绑定ViewHolder对象
}
else{
holder = (ViewHolder)convertView.getTag();//取出ViewHolder对象
}
/**设置TextView显示的内容,即我们存放在动态数组中的数据*/
holder.title.setText(getDate().get(position).get("ItemTitle").toString());
holder.text.setText(getDate().get(position).get("ItemText").toString());
return convertView;
}
}
/**存放控件*/
publicfinalclass ViewHolder{
public TextView title;
public TextView text;
public Button bt;
}
这里ViewHolder的作用其实很明显了,ViewHolder中持有的组件和converView中的组件指向同一个对象,所以这里使用ViewHolder就是替换掉findViewById。