您的位置:首页 > 编程语言

打造万能Viewholder,告别重复代码

2016-05-11 12:03 204 查看
每次写ListView显示列表都会重复写出if(convertview == null){}else{} 这些重复的代码,既然是重复的,肯定是可以提取复用的。。。

开始咯:

首先CommonAdapter类继承BaseAdapter并实现其方法,因为我们要做到灵活性,所以实体类,item布局都是要传进来的

public CommonAdapter(Context context, List<T> datas, int layoutId) {

this.mContext = context;

this.mInflater = LayoutInflater.from(context);

this.mDatas = datas;

this.layoutId = layoutId;

}

实现的BaseAdapter的类:

@Override

public int getCount() {

return mDatas.size();

}

@Override

public T getItem(int position) {

return mDatas.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

return null;

}

因为我们要使用ViewHolder来进行复用,所以开始编写ViewHolder类:

传统模式需要使用convertView.setTag(holder)将holder和adapter结合起来,所以我们现在需要将各种控件存储起来,然后再需要使用的地方取出这个控件进行使用就好了,在这里推荐使用SparseArray,实际上它内部也是维护的一个map集合,但是它比HaseMap效率要更高,可以看下官方解释

SparseArrays map integers to Objects. Unlike a normal array of Objects,there can be gaps in the indices. It is intended to be more memory efficient than using a HashMap to map Integers to Objects, both because it avoids auto-boxing keys and its data structure
doesn't rely on an extra entry object for each mapping.

private SparseArray<View> mViews;

我们可以开始编写一个ViewHolder的入口来供Adapter中的getView()方法调用

public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {

if (convertView == null) {

return new ViewHolder(context, parent, layoutId, position);

} else {

ViewHolder holder = (ViewHolder) convertView.getTag();

holder.mPosition = position;

return holder;

}

}

还是和传统模式的复用convertView一样的,当convertView不为空的时候,还是使用getTag(),当为空的时候通过使用new ViewHolder来进行初始化操作

public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {

this.mPosition = position;

this.mViews = new SparseArray<View>();

mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);

mConvertView.setTag(this);

}

ViewHolder里面传入我们需要的参数,当然包括item布局文件

有了这样一个ViewHolder类之后,并且提供了调用入口,这时候我们就可以在BaseAdapter中的getView()中进行调用了

@Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent, layoutId, position);

convert(viewHolder, getItem(position));

return viewHolder.getConvertView();

}

这里返回的是Viewholder中的getConvertView()

public View getConvertView() {

return mConvertView;

}

getView中我们对外提供了一个抽象方法convert()来供调用,返回了holder和我们的实体

public abstract void convert(ViewHolder holder, T t);

好了,CommonAdapter中基本就需要这些东西了

现在回到我们的ViewHolder类中,要使用ViewHolder,所以我们要怎么获取到控件呢

上面有讲到过,使用SparseArray来存储View控件

public <T extends View> T getView(int viewId) {

View view = mViews.get(viewId);

if (view == null) {

view = mConvertView.findViewById(viewId);

mViews.put(viewId, view);

}

return (T) view;

}

和HashMap一样,通过key来获取value,如果没有就使用convertView来findViewById()来获取控件,再添加到集合里并返回

到此我们的ViewHolder就已经编写差不多了

那如何使用呢?

CommonAdapter<MenuEntity> adapter = new CommonAdapter<MenuEntity>(context,menus,R.layout.item_list) {

@Override

public void convert(ViewHolder holder, MenuEntity menuEntity) {

TextView tv = holder.getView(R.id.tv);

tv_kind_name.setText(menuEntity.name);

}

};

可以直接在MainActivity中使用内部类来实现重写convert(),当然也可以重新新建一个类来继承我们的CommonAdapter,然后实现里面的方法咯

为了更简洁,我们还可以做如下优化:

/**

* 设置TextView的值

*

* @param viewId

* @param value

* @return

*/

public ViewHolder setText(int viewId, String value) {

TextView textView = getView(viewId);

textView.setText(value);

return this;

}

public ViewHolder setImageResource(int viewId, int resId) {

ImageView view = getView(viewId);

view.setImageResource(resId);

return this;

}

public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) {

ImageView view = getView(viewId);

view.setImageBitmap(bitmap);

return this;

}

我们可以直接在ViewHolder类中添加如是方法,获取控件并设置值,这个时候我们的convert中就可以变成这样:

CommonAdapter<MenuEntity> adapter = new CommonAdapter<MenuEntity>(context,menus,R.layout.item_gamelist_kind_list) {

@Override

public void convert(ViewHolder holder, MenuEntity menuEntity) {

holder.setText(R.id.tv_kind_name,menuEntity.menuName);

}

};

并且还可以连" . " 哦~

好了 至此我们的类已经全部编写完成,以后我们每次要使用BaseAdapter的时候就只需要new CommonAdapter就好了,是不是很简洁 @@

附上Utils源码连接:http://download.csdn.net/detail/flyingzhlunasea/9516487

欢迎指正!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: