在平时的项目中经常使用到listiview显示列表,很多时候,我们都是自定义一个adapter,然后继承BaseAdapter,并重写相关方法,最后在这个adapter类里写一个ViewHolder内容类,用来缓存控件用。为了提高效率,一个很实用的ViewHolder是很有必要的。
平时使用的:
public class MyListAdapter extends BaseAdapter {
private Context context;
private List<Data> list;
public MyListAdapter(Context context, List<Data> list) {
this.context = context;
this.list = list;
}
@Override
public int getCount() {
return list == null ? 0 : list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
MyViewHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item,viewGroup,false);
holder = new MyViewHolder();
holder.iv = (ImageView) convertView.findViewById(R.id.item_image);
holder.tv = (TextView) convertView.findViewById(R.id.item_text);
convertView.setTag(holder);
} else {
holder = (MyViewHolder) convertView.getTag();
}
Data data = (Data) getItem(position);
holder.iv.setImageResource(data.getImageId());
holder.tv.setText(data.getText());
return convertView;
}
public static class MyViewHolder {
ImageView iv;
TextView tv;
}
}
仔细观察上面的Adapter,的确是前三个方法一样。我们要是可以全部抽出来就好了。所以可以抽出来,写一个泛型使其变成一个抽象的基类,继承自BaseAdapter.其子类只需要去关心其getView方法。
public class ViewHolder {
// 添加私有构造函数防止外部实例化
private ViewHolder() {
}
/**
* 用来缓存控件,优化加载
* @param view itemView的布局
* @param id itemView布局中需要缓存控件的id
* @return 缓存后的控件(textView、imageView...等控件)
*/
@SuppressWarnings("unchecked")
public static View get(View view, int id) {
// 获取itemView的ViewHolder对象,并将其转型为SparseArray<View>
SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
if (viewHolder == null) {
// 如果viewHolder为空,就新建一个
viewHolder = new SparseArray<View>();
// 给view设置tag标签
view.setTag(viewHolder);
}
// 根据控件的id获取itemView布局的控件
View childView = viewHolder.get(id);
if(childView == null){
// 如果还没有缓存该控件,那么就根据itemView找到该控件
childView = view.findViewById(id);
// 缓存该控件
viewHolder.put(id, childView);
}
// 返回缓存好的控件
return childView;
}
}
在adapter中直接使用,会极大地提高开发效率
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
// 布局泵获取itemView的布局
convertView = inflater.inflate(R.layout.listview_test, null);
}
// 使用Viewholder类的静态方法缓存控件,并返回缓存后的控件
TextView tv_test = (TextView) ViewHolder.get(convertView, R.id.tv_test);
// 设置内容
tv_test.setText(list.get(position));
return convertView;
}