在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 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 <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中的控件;