以下內容為原創,歡迎轉載,轉載請注明
來自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3642849.html
在Android項目中,經常都會用到ListView這個控件,而相應的Adapter中getView()方法的編寫有一個標准的形式,如下:
1 @Override 2 public View getView(int position, View convertView, ViewGroup parent) { 3 ViewHolder holder; 4 if(null == convertView){ 5 holder = new ViewHolder(); 6 LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 7 convertView = mInflater.inflate(R.layout.item, null); 8 holder.btn = (Button) convertView.findViewById(R.id.btn); 9 holder.tv = (TextView) convertView.findViewById(R.id.tv); 10 holder.iv = (TextView) convertView.findViewById(R.id.iv); 11 12 convertView.setTag(holder); 13 }else{ 14 holder = (ViewHolder) convertView.getTag(); 15 } 16 final HashMap<String, Object> map = list.get(position); 17 18 holder.iv.setImageResource(Integer.valueOf(map.get("iv").toString())); 19 holder.tv.setText(map.get("tv").toString()); 20 21 holder.btn.setOnClickListener(new View.OnClickListener() { 22 @Override 23 public void onClick(View v) { 24 Toast.makeText(context, map.get("btn").toString(), Toast.LENGTH_SHORT).show(); 25 } 26 }); 27 28 return convertView; 29 } 30 31 class ViewHolder{ 32 Button btn; 33 ImageView iv; 34 TextView tv; 35 36 }
以下是碎碎念(想直接看代碼的,就跳過這段吧-_-!):
也就是說每次編寫Adapter都需要編寫class ViewHolder...、if(null == convertView){...等等。這些代碼跟業務邏輯關系不大,沒有必要每次都寫重復代碼,
所以,顯然有簡化代碼的余地。
既然我們的需求是不需要重復編寫ViewHolder等內部類,那就把它移到父類吧。
但是ViewHolder中在實際項目中有不同的View,那就用list存放起來吧,但是放在list中的話,怎么取出來?用index?顯然不是好的方法,不是有Resource Id這玩意,通過這個取不就好了么?所以以Resource Id為key放在Map中比較合適,但是既然以int(Resource Id)為key,那自然而然想到使用SparseArray了。
然后再把if(null == converView)...這些代碼統統移到父類中。
所以ABaseAdapter誕生了,代碼如下:
1 /** 2 * 實現對BaseAdapter中ViewHolder相關的簡化 3 * Created with IntelliJ IDEA. 4 * Author: wangjie email:tiantian.china.2@gmail.com 5 * Date: 14-4-2 6 * Time: 下午5:54 7 */ 8 public abstract class ABaseAdapter extends BaseAdapter{ 9 Context context; 10 11 protected ABaseAdapter(Context context) { 12 this.context = context; 13 } 14 15 protected ABaseAdapter() { 16 } 17 18 /** 19 * 各個控件的緩存 20 */ 21 public class ViewHolder{ 22 public SparseArray<View> views = new SparseArray<View>(); 23 24 /** 25 * 指定resId和類型即可獲取到相應的view 26 * @param convertView 27 * @param resId 28 * @param <T> 29 * @return 30 */ 31 public <T extends View> T obtainView(View convertView, int resId){ 32 View v = views.get(resId); 33 if(null == v){ 34 v = convertView.findViewById(resId); 35 views.put(resId, v); 36 } 37 return (T)v; 38 } 39 40 } 41 42 /** 43 * 改方法需要子類實現,需要返回item布局的resource id 44 * @return 45 */ 46 public abstract int itemLayoutRes(); 47 48 @Override 49 public View getView(int position, View convertView, ViewGroup parent) { 50 ViewHolder holder; 51 if(null == convertView){ 52 holder = new ViewHolder(); 53 convertView = LayoutInflater.from(context).inflate(itemLayoutRes(), null); 54 convertView.setTag(holder); 55 }else{ 56 holder = (ViewHolder) convertView.getTag(); 57 } 58 return getView(position, convertView, parent, holder); 59 } 60 61 /** 62 * 使用該getView方法替換原來的getView方法,需要子類實現 63 * @param position 64 * @param convertView 65 * @param parent 66 * @param holder 67 * @return 68 */ 69 public abstract View getView(int position, View convertView, ViewGroup parent, ViewHolder holder); 70 71 }
如上代碼:增加了一個itemLayoutRes()的抽象方法,該抽象方法提供給子類實現,返回item布局的resource id,為后面的getView方法提供調用。
可以看到上述代碼中,在系統的getView方法中,進行我們以前在BaseAdapter實現類中所做的事(初始化converView,並綁定ViewHolder作為tag),然后拋棄了系統提供的getView方法,直接去調用自己寫的getView抽象方法,這個getView方法是提供給子類去實現的,作用跟系統的getView一樣,但是這個getView方法中攜帶了一個ViewHolder對象,子類可以通過這個對象進行獲取item中的控件。
具體使用方式如下,比如創建了MyAdapter並繼承了ABaseAdapter:
注意,在構造方法中需要調用父類的構造方法:
1 public MyAdapter(Context context, List<HashMap<String, Object>> list) { 2 super(context); 3 this.list = list; 4 }
即,以上的“super(context);”必須調用。
接着實現itemLayoutRes()方法,返回item的布局:
1 @Override 2 public int itemLayoutRes() { 3 return R.layout.item; 4 }
getView方法中的實現如下:
1 @Override 2 public View getView(int position, View convertView, ViewGroup parent, ViewHolder holder) { 3 final HashMap<String, Object> map = list.get(position); 4 5 Button btn = holder.obtainView(convertView, R.id.item_btn); 6 ImageView iv = holder.obtainView(convertView, R.id.item_iv); 7 TextView tv = holder.obtainView(convertView, R.id.item_tv); 8 9 btn.setOnClickListener(new View.OnClickListener() { 10 @Override 11 public void onClick(View v) { 12 Toast.makeText(context, map.get("btn").toString(), Toast.LENGTH_SHORT).show(); 13 } 14 }); 15 16 iv.setImageResource(Integer.valueOf(map.get("iv").toString())); 17 tv.setText(map.get("tv").toString()); 18 19 return convertView; 20 }
如上代碼:調用holder.obtainView方法既可獲取item中的控件;