ListView的缓存机制

某天面试时被问到ListView的缓存机制,竟然不知道!赶紧来学习一下。
ListView的Adapter中都有一个方法getView(),平时我们就是在Adapter中用LayoutInflater从R.layout中拿取布局id然后填充为一个View返回,但是我却忽略了这个方法的第二个参数convertView,每次都通过inflate()方法去创建一个新的View然后从中findViewByID,造成性能的浪费。
这个convertView提供了一个对View对象复用的方法。当listview中的项目被滑出屏幕时,会被放入一个recycleBin中;新项目即将滑入屏幕时,adapter会从recycleBin中拿取一个作为getView的参数——convertView。需要注意的是这里复用的是View对象,而不是对象的内容,因此,当我们拿到这个convertView时,还要对其内容根据position指示的列表内容进行变更。
同时,我们也知道findViewByID也是比较耗时的,我们既然可以复用View,那View中的对象能不能复用呢?显然是可以的。View中都有一个getTag()和setTag()方法,而这个Tag是一个Object类型的,我们在首次创建View时,将根据id拿到的控件存入这个View的tag中,下次直接拿取tag就可以对数据进行操作了。

修改前的代码

public View getView(int position, View convertView, ViewGroup parent) {
    View v;
    v=LayoutInflater.from(parent.getContext()).inflate(R.layout.onenumber_layout,parent,false);
    // 填充,耗时耗内存
    TextView tv = v.findViewById(R.id.tv);
    // 寻找,耗时    
    tv.setText(position+"");
    // 根据position填充正确内容
    return v;
}

修改后的代码

public View getView(int position, View convertView, ViewGroup parent) {
View v;
if(convertView==null) {
v=LayoutInflater.from(parent.getContext()).inflate(R.layout.onenumber_layout,parent,false);
TextView tv = v.findViewById(R.id.tv);
tv.setText(position+"");
v.setTag(tv);
// 如果有多个控件,可以使用ArrayList或者Object[]进行存储。
}else {
v = convertView;
// 复用
TextView tv = ((TextView) v.getTag());
// 复用
tv.setText(position+"");
// 根据position填充正确内容
}
return v;
}

上一篇:Flutter中ListView加载图片数据的优化


下一篇:winform通过ListView绑定数据库数据源