传统的ListView写法
传统的ListView方法是每个ListView都要一个Adapter,这个Adapter继承BaseAdapter,重写四个方法。在getView()方法中获取各种View然后set。高级一点的写法就是使用ViewHolder缓存已经加载的View,然后再获取。这种写法对于ListView数目较少时比较合适,对于实际项目来说并不合适。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| ViewHolder viewHolder; View view; if (convertView == null) { view = mInflater.inflate(R.layout.item, null); viewHolder = new ViewHolder(); viewHolder.tv_title = (TextView) view.findViewById(R.id.tv_title); viewHolder.tv_content = (TextView) view.findViewById(R.id.tv_content); viewHolder.tv_time = (TextView) view.findViewById(R.id.tv_time); viewHolder.tv_phone = (TextView) view.findViewById(R.id.tv_phone);
view.setTag(viewHolder); } else { view=convertView; viewHolder = (ViewHolder) view.getTag();
} Bean bean = getItem(position); viewHolder.tv_title.setText(bean.getTitle()); viewHolder.tv_content.setText(bean.getDescribe()); viewHolder.tv_time.setText(bean.getTime()); viewHolder.tv_phone.setText(bean.getPhone());
return view; }
private class ViewHolder { TextView tv_title; TextView tv_content; TextView tv_time; TextView tv_phone; }
|
Adapter优化
ViewHolder的封装
在通常的写法中,用成员变量来保存View,而在这里采用SparseArray来保存View(SparseArray是android里为这样的Hashmap而专门写的class,目的是提高效率)。代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| private SparseArray<View> mViews; private int position; private View mConvertView;
public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) { this.position = position; this.mViews = new SparseArray<>(); mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false); mConvertView.setTag(this);
}
*提供入口方法 */ public static ViewHolder get(Context context, View convertView, ViewGroup parent, int position, int layoutId) { if (convertView == null) { return new ViewHolder(context, parent, layoutId, position); } else { ViewHolder holder = (ViewHolder) convertView.getTag(); holder.position = position; return holder; }
}
* 通过viewId获取控件 *返回一个View的子类 * @return */ 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;
}
public View getConvertView() { return mConvertView; }
public ViewHolder setText(int viewId, String text) { TextView tv = getView(viewId); tv.setText(text); return this; }
|
Adapter的封装
创建抽象类CommonAdapter,使其继承BaseAdapter,重写四个方法。在重写getView()方法的时候,就可以使用ViewHolder.get()这个入口方法了。最后创建抽象方法convert(),参数分别为ViewHolder和T,第一个参数旨在让用户取得ViewHolder对象来调用其方法;第二个参数为泛型T,指定Java Bean的类型。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public abstract class CommonAdapter<T> extends BaseAdapter {
protected List<T> mList; protected Context mContext; protected LayoutInflater mInflater;
public CommonAdapter(Context context, List<T> mList) { this.mList = mList; this.mContext = context; mInflater = LayoutInflater.from(context); }
@Override public int getCount() { return mList.size(); }
@Override public T getItem(int position) { return mList.get(position); }
@Override public long getItemId(int position) { return position; }
@Override public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = ViewHolder.get(mContext, convertView, parent, position, R.layout.item); convert(holder, getItem(position)); return holder.getConvertView(); }
public abstract void convert(ViewHolder holder, T t); }
|
以上通过对ViewHolder和Adapter的封装,是的我们在使用ListView的时候变得十分简单:直接继承CommonAdapter重写convert()方法即可。甚至为了简便,可以直接在setAdapter的时候新建内部类,省去了继承CommonAdapter的过程。以后再使用的时候直接复制这些代码即可。
1 2 3 4 5 6 7 8 9
| mListView.setAdapter(new CommonAdapter<Bean>(MainActivity.this, mList) { @Override public void convert(ViewHolder holder, Bean bean) { holder.setText(R.id.tv_title, bean.getTitle()) .setText(R.id.tv_content, bean.getDescribe()) .setText(R.id.tv_time, bean.getTime()) .setText(R.id.tv_phone, bean.getPhone()); } });
|