標籤:
在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)
主要是為了擷取到布局中的控制項,這個也只能自己手動擷取了
Android 簡單的MyBaseAdapter