Android 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