Android BaseAdapter提升效能的建議實作方式


BaseAdapter為自訂ListViewGridViewSpinner版面時,常需要實作的接合器(Adapter)。實作BaseAdapter時必須要謹慎小心,否則將會大大影響到執行效能,可以參考本篇文章提供的方式,來實作出效能不錯的BaseAdapter

實作BaseAdapter

BaseAdapter為實作ListAdapter和SpinnerAdapter介面(Interface)的抽象類別(Abstract Class),通常我們會建立一個獨立的.java檔案來繼承(Extend)BaseAdapter。繼承了BaseAdapter後,需要實作出以下幾個抽象方法(Abstract Method):

偷懶實作BaseAdapter

如果要快速地實作出BaseAdapter,以在ListView中顯示出JSONArray中的字串為例子,可以寫成以下的程式,:

執行結果如下,確實將JSONArray裡存放的字串都顯示出來了:

Android BaseAdapter提升效能的建議實作方式

但是用這種方式的話,每次當ListView變動(拉動捲軸或是資料改變)後,執行覆寫的getView方法時,都需要再inflate一次layout,並且重新使用findViewById抓取layout中View的參考值。拉動一下ListView後,再查看counter變數紀錄的值的話,就會發現inflate的次數居然輕易的就高達上千次。重複的動作實在是做太多了,而且如果layout中的元件很多的話,將會花上不少時間在重新inflate上。當然,如果不是使用inflate Layout的方式來排版,而是自己使用addView方法來排的話,也還是會需要在呼叫getView方法時一直重新addView。因此這樣的寫法會嚴重造成程式執行效能的低落。

Android BaseAdapter提升效能的建議實作方式

建議實作BaseAdapter的方式

先釐清BaseAdapter的資料項目(Item)數量是否會變動
固定的項目數量

一開始在實體化BaseAdapter時,將資料以固定陣列等方式傳進BaseAdapter建構子中即可。

變動的項目數量

一開始在實體化BaseAdapter時,將資料以可動陣列或是集合的方式傳進BaseAdapter建構子中即可,往後如果項目數量有變動的話,直接改變陣列或是集合後,使用BaseAdapter提供的notifyDataSetChanged方法來通知View資料已改變。千萬不要重新建立一個新的陣列或是集合,再使用setAdapter的方式將重新new出來的BaseAdapter指定給View,這種作法是效能最差的。

如果預期資料變化不會很大,同一個View應只在初始化時,new出一個BaseAdapter並使用setAdapter方法指定給View

如果預期資料變化不會太大,則只在Activity的onCreate階段或是Fragment的onCreateView階段時,new出一個BaseAdapter並使用setAdapter方法將BaseAdapter指定給View。如果後來資料有變動,使用BaseAdapter的notifyDataSetChanged方法來通知View進行更新即可。為了方便,可以在setAdapter前後,將BaseAdapter的參考以物件變數記下。

使用setAdapter方法後,View的狀態會重置,焦點將會移動到第一個項目;使用notifyDataSetChanged方法後,View的狀態不會重置,僅改變有變動的部份,焦點會保留在原本的位置。

避免一直重新inflate Layout

就是本文一開始提到的懶人實作法出現的問題。事實上,BaseAdapter會紀錄不同位置下的convertView物件。此處所說的位置並不是只資料項目在陣列或是集合內的position,而是資料項目在View上顯示的位置。也就是說,先前已經inflate過Layout,是會儲存在記憶體中的。getView方法所傳入的convertView參數,就是先前這個View的位置上使用getView方法傳回的View,如果沒有,就是null。所以,我們可以利用這已經inflate的convertView,再另外紀錄這convertView下的View的參考,就不用在getView時每次都去inflate Layout和findViewByID,或是addView了!

紀錄convertView下的View的參考的方式,可以另外實作一個class來紀錄,可以利用View所提供的Tag功能,將另外實作並實體化出的類別物件存進View的Tag欄位。

程式可以撰寫成如下:

隨便拉動套用這個BaseAdapterListView,發現counter變數並沒有明顯的增長,而且操作上明顯變順了!

Android BaseAdapter提升效能的建議實作方式

關於作者

Magic Len

各位好,我是Magic Len,是這網站的管理員。我是台灣台中大肚山上人,畢業於台中高工資訊科和台灣科技大學資訊工程系,曾在桃機航警局服役。我熱愛自然也熱愛科學,喜歡和別人分享自己的知識與經驗。如果你有興趣認識我,可以加我的Facebook,並且請註明是從MagicLen來的。

相關文章