相信搞过android开发的同志都知道在构建视图列表ListView的时候,总是会面对着这么一个问题,就是为了提高程序的流畅度和应用效率。而在每一行View的构建中加上一层缓存,也就是所谓的ViewHolder。
普遍的做法就是下述的基本实现.
class ViewHolder{
....
}
ViewHolder holder;
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
holder=new ViewHolder();
convertView.setTag(holder);
}else
holder= (ViewHolder)convertView.getTag();
....
return convertView;
}
只是,在实际的开发过程中,你会发现,每次的定义列表,你就得写一次与适配器Adapter相关的Holder。代码就显得相当亘余。先前在一篇博文看到,有人是将holder放到Map里的做法,觉得浪费了资源,而且也达不到我想要精简代码的目的。所以,为了偷懒,达到重用目的。于是小编利用工厂模式及泛型代码如下:
程序的通用适配器 AppAdapter
public abstract class AppAdapter<T> extends BaseAdapter {
protected Context ctx;
protected List<T> list;
protected Map<String, T> map;
protected LayoutInflater inflater;
public AppAdapter(Context ctx, List<T> list) {
this.ctx = ctx;
this.list = list;
this.inflater = LayoutInflater.from(ctx);
}
@Override
public int getCount() {
if (list == null)
return 0;
return list.size();
}
@Override
public T getItem(int position) {
if (list == null || position >= list.size())
return null;
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public abstract int getLayout();
public abstract Class<? extends BaseHolder<T>> getClazz();
/**
* 进行控件装配
*/
public abstract void assignment(int position, BaseHolder<T> baseHolder);
BaseHolder<T> holder;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
holder = getHolder(position, convertView);
assignment(position, holder);
return holder.getConvertView();
}
@SuppressWarnings("unchecked")
public BaseHolder<T> getHolder(int position, View convertView) {
BaseHolder<T> holder = null;
if (convertView == null) {
convertView = inflater.inflate(getLayout(), null);
try {
// 如果Holder处于内部类,那么实例化会失败,需要定义为public static
holder = (BaseHolder<T>) getClazz().newInstance();
holder.setConvertView(convertView);
holder.setCtx(ctx);
holder.setList(list);
holder.setPosition(position);
holder.init();
convertView.setTag(holder);
} catch (Exception e) {
e.printStackTrace();
}
} else {
holder = (BaseHolder<T>) convertView.getTag();
}
return holder;
}
}
缓存持有者BaseHolder
import java.util.List;
import android.content.Context;
import android.view.View;
public abstract class BaseHolder<T> {
private Context ctx;
private List<T> list;
private View convertView;
private int position;
private SparseArray<View> map_view;
public abstract void init();
@SuppressWarnings("unchecked")
public <T extends View> T getView(int id) {
if (map_view == null) {
map_view = new SparseArray<View>();
}
View childView = map_view.get(id);
if (childView == null) {
childView = this.getConvertView().findViewById(id);
map_view.put(id, childView);
}
return (T) childView;
}
public void setCtx(Context ctx) {
this.ctx = ctx;
}
public void setList(List<T> list) {
this.list = list;
}
public void setConvertView(View convertView) {
this.convertView = convertView;
}
public void setPosition(int position) {
this.position = position;
}
public Context getCtx() {
return ctx;
}
public List<T> getList() {
return list;
}
public View getConvertView() {
return convertView;
}
public int getPosition() {
return position;
}
}
没一个自定义的适配器只要继承AppAdapter<T>,然后修复好引用的方法即可,assignment函数里就可以实现该行的视图数据绑定和控件生成
import java.util.List;
import net.ceogo.app.ui.widget.AppAdapter;
import net.ceogo.app.ui.widget.BaseHolder;
import android.content.Context;
public class MyMessageAdapter extends AppAdapter<MyMessage> {
public MyMessageAdapter(Context ctx, List<MyMessage> list) {
super(ctx, list);
}
@Override
public int getLayout() {
return R.layout.item_mymessage;
}
@Override
public Class<? extends BaseHolder<MyMessage>> getClazz() {
return MyMessageItemHolder.class;
}
//不在内部定义可不用使用static
public static class MyMessageItemHolder{
//....
<pre name="code" class="java"> public TextView tv_title;
public void init(){ //这里可以获取该行的各种参数,position和context,或者进行事件绑定
<pre name="code" class="java"> this.tv_title=(TextView)findViewById(R.id.tv_title);
}
}
MyMessageItemHolder holder;
MyMessage myMessage;
@Override
public void assignment(int position, BaseHolder<MyMessage> baseHolder) {
holder = (MyMessageItemHolder) baseHolder;
myMessage = list.get(position);
if (myMessage != null) {
holder.tv_title.setText(myMessage.getTitle());
}
}
}