[Android]對BaseAdapter中ViewHolder編寫簡化

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

 

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *