在Android开发中经常用到ListView列表,于是Adapter也就比较常用的了, 而实际项目中稍微复杂点的基本都会用到BaseAdapter, 大家都知道继承自BaseAdapter必须要重写getCount(), getItem(), getItemId(), getView()这几个方法, 而且可能为了优化列表的加载还还会经常采用ViewHoder模式, 试想列表多了估计都写烦了吧,那么今天就来来一种通用、简洁的Adapter,以后你就可以几行代码搞定一个复杂的Adapter了。
通用的SimpleBaseAdapter
首先我们来解决每次都重写BaseAdapter的那几个方法的问题,解决方案很简单,直接写一个抽象的MyBaseAdapter,代码如下
package cn.wangxn.app.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import java.util.List; /** * * @Description: * @Title: MyBaseAdapter * @author: wangxn * @date: 2015/6/29 * * 泛型 T : 对应javaBean的类型 * E : 对应 ViewHolder的类型 */ public abstract class MyBaseAdapter<T, E> extends BaseAdapter { private Class<E> holderClass; //ViewHolder类的Class private E holder; //ViewHolder的实例 private List<T> list; //adapter对应的数据集合 private Context context; //上下文 private int resLayoutId; //条目资源的布局id /** *构造方法 必须是有4个参数的构造方法 *@param list 对应javabean的集合的引用 *@param context 对应上下文 *@param c 对应ViewHolder的Class, *@param resLayoutId 对应的是条目Item的布局资源id */ public MyBaseAdapter(List<T> list, Context context, Class<E> c, int resLayoutId) { this.list = list; this.context = context; this.resLayoutId = resLayoutId; this.holderClass = c; } @Override public int getCount() { if (list != null && list.size() > 0) { return list.size(); } return 0; } @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 parent) { E holder = null; //申明ViewHolder类实例 if (convertView == null) { convertView = View.inflate(context, resLayoutId, null); //获取到convertView try { holder = getObject(holderClass); //对viewHolder进行实例化 } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } if (holder != null){ findHolderViews(convertView, holder); // 找到convertView布局中的各种控件 convertView.setTag(holder); //将viewHolder设置为convertView的tag,重复利用 } } else { holder = (E) convertView.getTag(); //从convertView的tag中拿去内容转化成viewHolder } T bean = list.get(position); //拿取单条数据 if (holder != null) { setHolderView(holder, bean); //将单条数据和holder中对应的内容进行绑定,以及设置 } return convertView; //返回convertView } /** *抽象方法,需要自己实现, 将集合中的单挑数据javaBean和 布局进行绑定设置 */ protected abstract void setHolderView(E holder, T bean); /** *抽象方法,需要自己实现, 需要找到布局中的各个控件,findViewById */ protected abstract void findHolderViews(View convertView, E holder); /** * 实例化ViewHolder对象需要调用的方法, * ViewHolder对象需要提供默认的无参构造方法 */ private <T> T getObject(Class<T> c) throws IllegalAccessException, InstantiationException { T t = c.newInstance(); return t; } }
要使用这个MyBaseAdapter,
需要继承MyBaseAdapter, 需要实现2个抽象方法,
protected abstract void setHolderView(E holder, T bean){ } protected abstract void findHolderViews(View convertView, E holder){ }
需要实现由4个参数的构造方法.
public MyBaseAdapter(List<T> list, Context context, Class<E> c, int resLayoutId) { super(list,context,c,resLayoutId); }
同时需要提供2个泛型类型
javaBean //对应数据
ViewHolder //对应布局中的控件
一个实现的例子:
public class TradeListAdapter extends MyBaseAdapter<TradeDetail, TradeDetailHolder> { public TradeListAdapter(List<TradeDetail> list, Context context, Class<TradeDetailHolder> holderClass, int resLayoutId) { super(list, context, holderClass, resLayoutId); } @Override protected void setHolderView(TradeDetailHolder holder, final TradeDetail bean) { StringBuilder sb = new StringBuilder(""); if (!StrUtil.isEmpty(bean.carBrandName)) { sb.append(bean.carBrandName); if (!StrUtil.isEmpty(bean.carSubBrandName)) { sb.append(bean.carSubBrandName); if (!StrUtil.isEmpty(bean.carTypeName)) { sb.append(bean.carTypeName); } } } holder.tv_car_name.setText(sb.toString()); if (!StrUtil.isEmpty(bean.tradeAmount)) { holder.tv_rent_price.setText("¥" + bean.tradeAmount); } else { holder.tv_rent_price.setText(""); } if (!StrUtil.isEmpty(bean.tradeDate)) { holder.tv_date_time.setText(bean.tradeDate); } else { holder.tv_date_time.setText(""); } if (!StrUtil.isEmpty(bean.orderId)) { holder.btn_detail.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Bundle bundle = new Bundle(); bundle.putString("orderId", bean.orderId); startActivity(OrderDetailActivity.class, bundle); } }); } } @Override protected void findHolderViews(View contaier, TradeDetailHolder holder) { holder.tv_car_name = (TextView) contaier.findViewById(R.id.tv_car_name); holder.tv_rent_price = (TextView) contaier.findViewById(R.id.tv_rent_price); holder.tv_date_time = (TextView) contaier.findViewById(R.id.tv_date_time); holder.btn_detail = (Button) contaier.findViewById(R.id.btn_detail); } }
用到的TradeDetailHolder
import android.widget.Button; import android.widget.TextView; public class TradeDetailHolder { public TradeDetailHolder() { //提供下默认的构造方法,防止有些时候报错, } public TextView tv_car_name; public TextView tv_rent_price; public TextView tv_date_time; public Button btn_detail; }
用到的javaBean:TradeDetail
public class TradeDetail { public String orderId;// string 订单ID public String orderNumber; // string 订单编号 public String carBrandName; // string 品牌 public String carSubBrandName; // string 二级品牌 public String carTypeName; // string 型号 public String tradeAmount; // string 价格 public String tradeDate;// string 日期 }
好处:
这样之后,可以省去那些每一个BaseAdapter都要写的方法getCount(), getItem(), getItemId(), getView()
只关注最核心的数据和界面控件之间的逻辑处理,这部分逻辑处理全部在
setHolderView(JAVABEAN b, VIEWHOLDER holder)
这个方法里去实现.
而方法
protected void findHolderViews(View convertView, ViewHolder holder)
主要是为了获取到布局中的控件,这个也只能自己手动获取了