在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)
主要是为了获取到布局中的控件,这个也只能自己手动获取了