目前在写项目的过程中,虽然 RecyclerView 已经出来很久了,但是仍有一部分朋友(包括我)再继续使用着 ListView,GridView .
在使用的过程中,使用 ViewHolder 进行 ListView,GridView 的优化,是必不可少的,所以,我们每次在 getView 的方法中 都会去利用 ViewHolder 去进行 View 的复用。
写法如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//ViewHolder
ViewHolder viewHolder=null;
//绘制每一项的时候先判断convertView是否为空,不为空,则else里面去复用,为空,则重新赋予item布局
if (convertView == null) {
//new出ViewHolder ,初始化布局文件
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_test, null);
viewHolder.tv_name= (TextView) convertView.findViewById(R.id.tv_name);
//调用convertView的setTag方法,将viewHolder放入进去,用于下次复用
convertView.setTag(viewHolder);
} else {
//复用已经存在的item的项
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tv_name.setText(listBeans.get(position));
return convertView;
}
class ViewHolder {
TextView tv_name;
}
这样的写法使得我们即便 Item 里面只有一两个控件,也都要去写一个 ViewHolder ,这也就算了,如果 Item 里面控件多了,我们就需要花费一定的时间先去创建 ViewHolder。 不知道有没有朋友想过寻找一些简化的方法。
我这里整理出一个简化使用 ViewHolder 的方法,相对于创建上面的 getTag() setTag(), 要优雅许多,并且在使用上,也避免了做一些重复性的工作。
这里直接写为一个工具类:
public class ViewHolder {
public static <t extends="" view=""> T get(View view, int id) {
SparseArray<view> viewHolder = (SparseArray<view>) view.getTag();
if (viewHolder == null) {
viewHolder = new SparseArray<view>();
view.setTag(viewHolder);
}
View childView = viewHolder.get(id);
if (childView == null) {
childView = view.findViewById(id);
viewHolder.put(id, childView);
}
return (T) childView;
}
}
然后在 getView 中使用方式为:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_test, null);
}
TextView tv_name = ViewHolder.get(convertView , R.id.tv_name);
tv_name.setText(listBeans.get(position));
return convertView;
}
二、学习ViewHolder中get()方法的思路
ViewHolder中的get()方法里,使用了一个类:SparseArray,该类是android.util包中提供的一个类,主要用于代替Map<Integer, Object>,SparseArray内部通过键值对存放数据,其中键是整型数据,SparseArray的内部采用折半查找的思想,和普通的Map<Integer, Object>相比,拥有更好的性能,下面分析一下ViewHolder.get()方法:
public class ViewHolder {
@SuppressWarnings("unchecked")
public static <T extends View> T get(View view, int id){
//从convertView中获取tag,SparseArray里面存放View和View对应的id,通过View的id来查找View
SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
//如果获取不到,则创建SparseArray对象,并将SparseArray对象放入convertView的tag中
if(viewHolder == null){
viewHolder = new SparseArray<View>();
view.setTag(viewHolder);
}
//通过View的id来获取View,在SparseArray的内部使用的折半查找
View childView = viewHolder.get(id);
//如果在SparseArray中没有对应的id,则通过findViewById来获取View
if(childView == null){
childView = view.findViewById(id);
//将获取到的View和与View对应的id存入SparseArray中
viewHolder.put(id, childView);
}
//返回值是方法的第二个参数id对应的View
return (T) childView;
}
}