Android中的自定義Adapter(繼承自BaseAdapter)——與系統Adapter的調用方法一致——含ViewHolder顯示效率的優化

轉自   http://blog.csdn.net/listening_music/article/details/6965755


Android中很多地方使用的是適配器(Adapter)機制,那我們就要好好把這個Adapter利用起來,並且用出自己的特色,來符合我們自行設計的需要嘍~~~

        下面先上一個例子,是使用ViewHolder進行顯示效率優化過的工程:

        

[java] view plain copy
 print?
  1. package com.test.listviewsimpleadapter;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import android.app.AlertDialog;  
  9. import android.app.ListActivity;  
  10. import android.content.Context;  
  11. import android.content.DialogInterface;  
  12. import android.os.Bundle;  
  13. import android.util.Log;  
  14. import android.view.LayoutInflater;  
  15. import android.view.View;  
  16. import android.view.ViewGroup;  
  17. import android.widget.BaseAdapter;  
  18. import android.widget.Button;  
  19. import android.widget.ImageView;  
  20. import android.widget.ListView;  
  21. import android.widget.TextView;  
  22.   
  23. /* listView在開始繪製的時候,系統首先調用getCount()函數,根據他的返回值得到listView的長 
  24.  * 度(這也是爲什麼在開始的第一張圖特別的標出列表長度),然後根據這個長度,調用getView()逐 
  25.  * 一繪製每一行。如果你的getCount()返回值是0的話,列表將不顯示同樣return 1,就只顯示一行。 
  26.  * 系統顯示列表時,首先實例化一個適配器(這裏將實例化自定義的適配器)。當手動完成適配時,必 
  27.  * 須手動映射數據,這需要重寫getView()方法。系統在繪製列表的每一行的時候將調用此方法。 
  28.  * getView()有三個參數,position表示將顯示的是第幾行,covertView是從佈局文件中inflate來的 
  29.  * 佈局。我們用LayoutInflater的方法將定義好的main.xml文件提取成View實例用來顯示。然後 
  30.  * 將xml文件中的各個組件實例化(簡單的findViewById()方法)。這樣便可以將數據對應到各個組件 
  31.  * 上了。但是按鈕爲了響應點擊事件,需要爲它添加點擊監聽器,這樣就能捕獲點擊事件。至此一個自定 
  32.  * 義的listView就完成了,現在讓我們回過頭從新審視這個過程。系統要繪製ListView了,他首先獲得 
  33.  * 要繪製的這個列表的長度,然後開始繪製第一行,怎麼繪製呢?調用getView()函數。在這個函數裏面 
  34.  * 首先獲得一個View(實際上是一個ViewGroup),然後再實例並設置各個組件,顯示之。好了,繪製完 
  35.  * 這一行了。那 再繪製下一行,直到繪完爲止。在實際的運行過程中會發現listView的每一行沒有焦點 
  36.  * 了,這是因爲Button搶奪了listView的焦點,只要佈局文件中將Button設置爲沒有焦點就OK了*/  
  37.   
  38. public class MyListView4 extends ListActivity {  
  39.   
  40.     private List<Map<String, Object>> mData;  
  41.   
  42.     @Override  
  43.     public void onCreate(Bundle savedInstanceState) {  
  44.         super.onCreate(savedInstanceState);  
  45.         mData = getData();  
  46.         MyAdapter adapter = new MyAdapter(this);  
  47.         setListAdapter(adapter);  
  48.     }  
  49.   
  50.     private List<Map<String, Object>> getData() {  
  51.         List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();  
  52.   
  53.         Map<String, Object> map = new HashMap<String, Object>();  
  54.         map.put("title""G1");  
  55.         map.put("info""google 1");  
  56.         map.put("img", R.drawable.i1);  
  57.         list.add(map);  
  58.   
  59.         map = new HashMap<String, Object>();  
  60.         map.put("title""G2");  
  61.         map.put("info""google 2");  
  62.         map.put("img", R.drawable.i2);  
  63.         list.add(map);  
  64.   
  65.         map = new HashMap<String, Object>();  
  66.         map.put("title""G3");  
  67.         map.put("info""google 3");  
  68.         map.put("img", R.drawable.i3);  
  69.         list.add(map);  
  70.   
  71.         return list;  
  72.     }  
  73.   
  74.     // ListView 中某項被選中後的邏輯  
  75.     @Override  
  76.     protected void onListItemClick(ListView l, View v, int position, long id) {  
  77.         Log.v("MyListView4-click", (String) mData.get(position).get("title"));  
  78.     }  
  79.   
  80.     /** 
  81.      * listview中點擊按鍵彈出對話框 
  82.      */  
  83.     public void showInfo() {  
  84.         new AlertDialog.Builder(this).setTitle("我的listview")  
  85.                 .setMessage("介紹...")  
  86.                 .setPositiveButton("確定"new DialogInterface.OnClickListener() {  
  87.                     @Override  
  88.                     public void onClick(DialogInterface dialog, int which) {  
  89.                     }  
  90.                 }).show();  
  91.     }  
  92.   
  93.     public final class ViewHolder {  
  94.         public ImageView img;  
  95.         public TextView title;  
  96.         public TextView info;  
  97.         public Button viewBtn;  
  98.     }  
  99.   
  100.     public class MyAdapter extends BaseAdapter {  
  101.   
  102.         private LayoutInflater mInflater;  
  103.   
  104.         public MyAdapter(Context context) {  
  105.             this.mInflater = LayoutInflater.from(context);  
  106.         }  
  107.   
  108.         @Override  
  109.         public int getCount() {  
  110.             // TODO Auto-generated method stub  
  111.             return mData.size();  
  112.         }  
  113.   
  114.         @Override  
  115.         public Object getItem(int arg0) {  
  116.             // TODO Auto-generated method stub  
  117.             return null;  
  118.         }  
  119.   
  120.         @Override  
  121.         public long getItemId(int arg0) {  
  122.             // TODO Auto-generated method stub  
  123.             return 0;  
  124.         }  
  125.   
  126.         @Override  
  127.         public View getView(int position, View convertView, ViewGroup parent) {  
  128.             // 顯示優化(只要之前顯示過的就可以不再再次從佈局文件讀取,直接從緩存中讀取——ViewHolder的作用)  
  129.             // 其實是setTag和getTag中Tag的作用  
  130.             ViewHolder holder = null;  
  131.             if (convertView == null) {// 如果是第一次顯示該頁面(要記得保存到viewholder中供下次直接從緩存中調用)  
  132.   
  133.                 holder = new ViewHolder();  
  134.   
  135.                 convertView = mInflater.inflate(R.layout.main, null);  
  136.                 // 以下爲保存這一屏的內容,供下次回到這一屏的時候直接refresh,而不用重讀佈局文件  
  137.                 holder.img = (ImageView) convertView.findViewById(R.id.img);  
  138.                 holder.title = (TextView) convertView.findViewById(R.id.title);  
  139.                 holder.info = (TextView) convertView.findViewById(R.id.info);  
  140.                 holder.viewBtn = (Button) convertView  
  141.                         .findViewById(R.id.view_btn);  
  142.                 convertView.setTag(holder);  
  143.   
  144.             } else {// 如果之前已經顯示過該頁面,則用viewholder中的緩存直接刷屏  
  145.   
  146.                 holder = (ViewHolder) convertView.getTag();  
  147.             }  
  148.   
  149.             holder.img.setBackgroundResource((Integer) mData.get(position).get(  
  150.                     "img"));  
  151.             holder.title.setText((String) mData.get(position).get("title"));  
  152.             holder.info.setText((String) mData.get(position).get("info"));  
  153.   
  154.             holder.viewBtn.setOnClickListener(new View.OnClickListener() {  
  155.   
  156.                 @Override  
  157.                 public void onClick(View v) {  
  158.                     showInfo();  
  159.                 }  
  160.             });  
  161.             return convertView;  
  162.         }  
  163.     }  
  164. }  

        下面是將自定義的Adapter的構造方法定義爲與系統的Adapter一致的工程,這樣大家在實例化自定義的Adapter時可以按照實例化系統的Adapter的參數安排來進行喲~

        

[java] view plain copy
 print?
  1. package com.test.listviewsimpleadapter;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import android.app.AlertDialog;  
  6. import android.content.Context;  
  7. import android.util.Log;  
  8. import android.view.LayoutInflater;  
  9. import android.view.View;  
  10. import android.view.ViewGroup;  
  11. import android.widget.BaseAdapter;  
  12. import android.widget.Button;  
  13. import android.widget.CheckBox;  
  14. import android.widget.CompoundButton;  
  15. import android.widget.ImageView;  
  16. import android.widget.TextView;  
  17. import android.widget.CompoundButton.OnCheckedChangeListener;  
  18. /** 
  19.  * @author Himi 
  20.  *  
  21.  */  
  22. public class MySimpleAdapter extends BaseAdapter {  
  23.     private LayoutInflater mInflater;  
  24.     private List<Map<String, Object>> list;  
  25.     private int layoutID;  
  26.     private String flag[];  
  27.     private int ItemIDs[];  
  28.     public MySimpleAdapter(Context context, List<Map<String, Object>> list,  
  29.             int layoutID, String flag[], int ItemIDs[]) {  
  30.         Log.i("TAG","構造方法");  
  31.         this.mInflater = LayoutInflater.from(context);  
  32.         this.list = list;  
  33.         this.layoutID = layoutID;  
  34.         this.flag = flag;  
  35.         this.ItemIDs = ItemIDs;  
  36.     }  
  37.     @Override  
  38.     public int getCount() {  
  39.         // TODO Auto-generated method stub  
  40.         return list.size();  
  41.     }  
  42.     @Override  
  43.     public Object getItem(int arg0) {  
  44.         // TODO Auto-generated method stub  
  45.         return 0;  
  46.     }  
  47.     @Override  
  48.     public long getItemId(int arg0) {  
  49.         // TODO Auto-generated method stub  
  50.         return 0;  
  51.     }  
  52.     @Override  
  53.     public View getView(int position, View convertView, ViewGroup parent) {  
  54.         convertView = mInflater.inflate(layoutID, null);  
  55.         for (int i = 0; i < flag.length; i++) {//備註1  
  56.             if (convertView.findViewById(ItemIDs[i]) instanceof ImageView) {  
  57.                 ImageView iv = (ImageView) convertView.findViewById(ItemIDs[i]);  
  58.                 iv.setBackgroundResource((Integer) list.get(position).get(  
  59.                         flag[i]));  
  60.             } else if (convertView.findViewById(ItemIDs[i]) instanceof TextView) {  
  61.                 TextView tv = (TextView) convertView.findViewById(ItemIDs[i]);  
  62.                 tv.setText((String) list.get(position).get(flag[i]));  
  63.             }else{  
  64.                 //...備註2  
  65.                 Log.i("TAG","else");  
  66.             }  
  67.         }  
  68.         addListener(convertView);  
  69.         return convertView;  
  70.     }  
  71. /** 
  72.  * 童鞋們只需要將需要設置監聽事件的組件寫在下面這方法裏就可以啦! 
  73.  * 別的不需要修改! 
  74.  * 備註3 
  75.  */  
  76.     public void addListener(View convertView) {  
  77.         ((Button)convertView.findViewById(R.id.btn)).setOnClickListener(  
  78.                 new View.OnClickListener() {  
  79.                     @Override  
  80.                     public void onClick(View v) {  
  81.                         new AlertDialog.Builder(LvSimpleAdapter.ma)  
  82.                         .setTitle("自定義通用SimpleAdapter")  
  83.                         .setMessage("按鈕成功觸發監聽事件!")  
  84.                         .show();  
  85.                         Log.i("TAG","Button");  
  86.                     }  
  87.                 });  
  88.         ((CheckBox)convertView.findViewById(R.id.cb)).  
  89.         setOnCheckedChangeListener(new OnCheckedChangeListener() {  
  90.             @Override  
  91.             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {  
  92.                 new AlertDialog.Builder(LvSimpleAdapter.ma)  
  93.                 .setTitle("自定義通用SimpleAdapter")  
  94.                 .setMessage("CheckBox成功觸發狀態改變監聽事件!")  
  95.                 .show();  
  96.                 Log.i("TAG","CheckBox");  
  97.             }  
  98.         });  
  99.     }  
  100. }  
        以上代碼的註釋都比較詳細,而且前面的Blog中也對Adapter進行過講解,這邊就不再說一遍啦~

        其中第二段代碼中沒有使用ViewHolder對顯示效率進行優化,大家可以參考第一段稍稍改動一下就OK了哈~


發佈了48 篇原創文章 · 獲贊 33 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章