對於Android程序員來說,BaseAdapter肯定不會陌生,靈活而優雅是BaseAdapter最大的特點。開發者可以通過構造BaseAdapter並搭載到ListView或者GridView這類多控件布局上面,實現軟件所需要的布局效果。同時,BaseAdapter也是適配器里面最基礎的一個類,其他的例如SimpleAdapter、ArrayAdapter都是直接或者間接繼承BaseAdapter,所以說學好BaseAdapter基本就熟練掌握了適配器的使用了。
本文需要具備一些Android基礎知識的前提下才能更好的理解,因為本文並不是介紹BaseAdapter的基本使用方法,如果對於BaseAdapter不了解可以去參考一下文檔。在這里主要是介紹一下BaseAdapter的實現細節和怎么優化BaseAdapter的設計,從而節省我們寶貴的手機運行資源。對於老鳥高手來說,這可能是一個常識了,還是主要給那些像我以前一樣剛剛入門的開發者的一點點參考,也希望高手來多多指正。
話不多說,我們看一看某些社交軟件的界面(網上找的。。。。。)
這個列表項就是用ListView作為布局,搭載SimpleAdapter或者BaseAdapter作為數據源做成的界面效果。一般來說,很多軟件的界面都運用這個方法來實現想要的布局效果。我在這里說明一下后面說到的名詞,首先這是一個列表項,里面有各個數據項,例如圖片+文件傳輸助手+test+時間就是一個數據項,它是一個View視圖,這張圖片里面一共就有8個數據項,由8個View視圖按垂直方向排列而成。OK,我們開始步入正題。
假設,我們還是用例子講解比較好理解,所以呢我們假設這個列表里面一共有40個數據項,而作為手機界面的限制,它一次只能顯示8個數據項,同時它的另外32個數據項是隱藏狀態。而顯示這8個數據項就需要8個View實例,也就是需要實例化8個View的子類來顯示內容,此時系統就有8個View實例占據內存空間。那如果我們把手指往下一滑動呢,自然頂端的數據項就會被隱藏,而底端的數據項自然就顯示出來,那么這時候需要在new一個新的View實例來嗎?如果還是繼續創建實例,那么系統內存空間就有9個View實例了,可是我們還是只需要8個View實例就可以在手機屏幕完全顯示,而頂端的被隱藏的實例話是可以不存在的了。所以這么來說,這樣就浪費了手機的運行資源了。
為了解決這個問題,我們在BaseAdapter中可以對View進行重用,也就是將被隱藏的View改變為將要顯示的View並返回出來。
在BaseAdapter中,這個抽象方法非常重要,它就是根據position的值返回對象的數據項的View視圖,所以我們主要也是圍繞這個方法來達到效率上優化的目的。
public View getView(int position, View convertView, ViewGroup parent) { return null; }
簡單介紹一下這個函數的參數,position是ID索引值,也就是ListView的對應的數據項的序號,而convertView則是View視圖復用的基礎,如果為第一個頁面的數據,它的值為null,所以我們可以根據convertView的值來決定我們是否要new一個View的實例出來。
參見下面代碼
1 @Override 2 public View getView(int position, View convertView, ViewGroup parent) { 3 if(convertView == null){ 4 convertView = new TextView(context);//新建一個字符串控件 5 ((TextView)convertView).setText(position);//實現其是第幾個數據項 6 } 7 else{ 8 ((TextView)convertView).setText(position);//重新修改其是第幾個數據項 9 } 10 return convertView; 11 }
為了簡單起來,我這里的View只是一個簡簡單單的字符串控件,在代碼中我們可以看到,先對convertView進行判斷,如果其值為null,則說明該方法此時返回的View是第一頁的視圖,所以需要new出一個View的實例,然后對其進行設置顯示的內容並返回(這里設置的內容為position)。如果其值不為null,則說明此時的View視圖是可以復用其他已經隱藏的View實例,而convertView的索引就是這個隱藏的實例,自然我們不用重新創建一個新的View實例而直接對convertView進行重新設置數值並返回便可。
這樣就保證了程序里面只有足夠界面顯示的View實例的個數存在,而不會有多余的View來占用系統資源,由此也提高了一點點效率。
這是BaseAdapter的效率優化的一個方面,接下來我們還要說一下另外一個方面,說明白了也就是一個小技巧來提高效率。對於一個BaseAdapter來說,顯示的界面肯定不是僅僅的一兩個字符串控件(不然我們就用ArrayAdapter了多簡便),而一般是加載一個根據layout生成的布局控件,相對來說這個的布局控件會比較復雜,我們會對其的子控件進行獲取並賦值返回,所以我們經常要調用findViewById()這個方法來或者子控件的引用。而findViewById()會比較消耗系統資源,頻繁的調用在我們快速滑動界面時會加重手機的負擔,所以我們也可以對這個地方進行一些小小的改進。
參考這個代碼
1 public class PersonAdapter extends BaseAdapter { 2 private List<Person> persons;//綁定的數據 3 private int resource;//綁定的Layout數據項界面 4 private LayoutInflater inflater;//布局填充服務 5 6 public PersonAdapter(Context context, List<Person> persons, int resource) { 7 this.persons = persons; 8 this.resource = resource; 9 inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 10 } 11 @Override 12 public int getCount() { 13 return persons.size(); 14 } 15 @Override 16 public Object getItem(int position) { 17 return persons.get(position); 18 } 19 @Override 20 public long getItemId(int position) { 21 return position; 22 } 23 @Override 24 public View getView(int position, View convertView, ViewGroup parent) { 25 TextView nameView = null; 26 TextView phoneView = null; 27 if(convertView == null){ 28 convertView = inflater.inflate(resource, null);//生成綁定數據的View界面 29 nameView = (TextView) convertView.findViewById(R.id.name); 30 phoneView = (TextView) convertView.findViewById(R.id.phone); 31 32 ViewCache cache = new ViewCache(); 33 cache.nameView = nameView; 34 cache.phoneView = phoneView; 35 convertView.setTag(cache); 36 }else{ 37 ViewCache cache = (ViewCache) convertView.getTag(); 38 nameView = cache.nameView; 39 phoneView = cache.phoneView; 40 } 41 Person person = persons.get(position); 42 //下面代碼實現數據綁定 43 nameView.setText(person.getName()); 44 phoneView.setText(person.getPhone()); 45 46 return convertView; 47 } 48 /** 49 *保存findViewById獲得的子控件索引的內部類 50 */ 51 private final class ViewCache{ 52 public TextView nameView; 53 public TextView phoneView; 54 } 55 }
重點還是放在getView()這個方法上。在代碼里面,我寫了一個ViewCache的私有內部類,主要用來保存要來復用的View所需要獲得的子控件的索引值。稍微解釋一下代碼,如果convertView為null,則說明需要new出一個View實例,在這里就是調用Inflater這個系統服務根據resource這個界面的ID值來生成一個View實例,然后用findViewById這個方法來或者其中的子控件的值,並保存在內部類ViewCache中,放入Tag中,setTag(object)是可以放入一個任意的類來保存成為緩存,因為其是Object。最后設置View子控件的內容並返回。如果不為null呢,現在則需要重用View實例了,所以我們也順帶重用一下保存在Tag里面的ViewCache的類成員變量的子控件索引值,而不需要重新去一個一個調用findViewById()這個方法,在界面足夠復雜時這樣是可以節省很多系統資源的。
這就是BaseAdapter提高效率的兩種小技巧,如果大牛有其他更好的技巧,也希望能分享分享用來學習一下。
作者:enjoy風鈴
出處:http://www.cnblogs.com/net168/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則下次不給你轉載了。