使用 ListView 元件時該注意的技巧 - II

在 使用 ListView 元件時該注意的技巧 - I 中,我們了解到 ListView 常用的技巧。在這一篇中,我們來看看當使用 ListView 時,可能犯的錯誤有哪些。

首先,如果你有寫自己的 ListAdapter,有些人會不曉得在 getView() 中,如何處理傳入的 convertView。

正確的處理方法,應該像底下範例一樣。

//refer to http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/List4.html  
public View getView(int position, View convertView, ViewGroup parent) {  
  SpeechView sv;  
  if (convertView == null) {  
    sv = new SpeechView(mContext, Shakespeare.TITLES[position],  
            Shakespeare.DIALOGUE[position]);  
  } else {  
    sv = (SpeechView) convertView;  
    sv.setTitle(Shakespeare.TITLES[position]);  
    sv.setDialogue(Shakespeare.DIALOGUE[position]);  
  }  
  return sv;  
} 

如果你不判斷 "if (convertView == null)",每次都呼叫 "sv = new SpeechView(...)",程式當然也會動,不過就會讓 Dalvik 每隔一陣子就瞎忙一通,回收不用的 View objects。這樣的結果,當然也會在使用者捲動時,造成不順的感覺。

第二個最常犯的錯誤就是下面這個例子。

    <ListView android:id="@android:id/list"  
      android:layout_width="match_parent"   
      android:layout_height="wrap_content"  
      android:layout_weight="1" />  

你看出問題在哪了嗎?如果你不知道答案的話,我建議你在自己的 ListAdapter 中的每個函數,都加個 Log.d() 追蹤一下這些函數的執行順序與次數。底下是我某個應用中,所印出來的結果。

    getCount()  
    getCount()  
    getCount()  
    getCount()  
    getView(): nPos=0, vConvert is null  
    getView(): nPos=1, vConvert is not null  
    getView(): nPos=2, vConvert is not null  
    getView(): nPos=3, vConvert is not null  
    getView(): nPos=4, vConvert is not null  
    getView(): nPos=5, vConvert is not null  
    getView(): nPos=6, vConvert is not null  
    getView(): nPos=7, vConvert is not null  
    getCount()  
    getCount()  
    getView(): nPos=0, vConvert is not null  
    getView(): nPos=1, vConvert is null  
    getView(): nPos=2, vConvert is null  
    getView(): nPos=3, vConvert is null  
    getView(): nPos=4, vConvert is null  
    getView(): nPos=5, vConvert is null  
    getView(): nPos=6, vConvert is null  
    getCount()  
    getCount()  
    getView(): nPos=0, vConvert is null  
    getView(): nPos=1, vConvert is not null  
    getView(): nPos=2, vConvert is not null  
    getView(): nPos=3, vConvert is not null  
    getView(): nPos=4, vConvert is not null  
    getView(): nPos=5, vConvert is not null  
    getView(): nPos=6, vConvert is not null  
    getView(): nPos=7, vConvert is not null  
    getCount()  
    getCount()  
    getCount()  
    getCount()  
    getView(): nPos=0, vConvert is not null  
    getView(): nPos=1, vConvert is not null  
    getView(): nPos=2, vConvert is not null  
    getView(): nPos=3, vConvert is not null  
    getView(): nPos=4, vConvert is not null  
    getView(): nPos=5, vConvert is not null  
    getView(): nPos=6, vConvert is not null  
    getView(): nPos=7, vConvert is not null  
    getCount()  
    getCount()  

整個畫面上,只顯示 7 個項目。怎麼 getView() 被呼叫了那麼多次?

這原因就出在 android:layout_height="wrap_content" 這行描述上。如果將這行改成 android:layout_height="0dip",結果就像下面這樣,getView() 的呼叫次數,完全符合原先的預期。

    getCount()  
    getCount()  
    getCount()  
    getCount()  
    getCount()  
    getView(): nPos=0, vConvert is null  
    getView(): nPos=1, vConvert is null  
    getView(): nPos=2, vConvert is null  
    getView(): nPos=3, vConvert is null  
    getView(): nPos=4, vConvert is null  
    getView(): nPos=5, vConvert is null  
    getView(): nPos=6, vConvert is null  
    getCount()  
    getCount()  
    getCount()  
    getCount()  

從這個結果中,我們也看到 getCount() 會被呼叫好幾次。在追蹤過原始碼後,我發現原始碼中並沒有存下 getCount() 的傳回結果。因此這 getCount() 會被呼叫這麼多次,並不是我們的問題。那我們唯一能做的事,就是讓 getCount() 執行的速度越快越好。

如果你有在 ListView 中,套用自己的 ListAdapter。我都會建議你在自己的 ListAdapter 中的每個函數,都加個 Log.d() 追蹤一下這些函數的執行順序與次數,是否都符合你的預期。很簡單的動作,但常會幫你找到不少的問題,分享給你。

你可能感兴趣的:(ListView)