ListView與Adapter使用要點

項目用到ListView,因爲要用到ImageView,圖片源不是在資源裏面的,無法使用資源ID,所以沒法直接使用SimpleAdapter,要本身寫一個Adapter。在使用ListView和Adapter須要注意如下幾點:java

 

1. Adapter.getView()android

 

public View getView(int position, View convertView, ViewGroup parent){...}緩存

 

這個方法就是用來得到指定位置要顯示的View。官網解釋以下:性能

Get a View that displays the data at the specified position in the data set. You can either create a View manually or inflate it from an XML layout file.優化

 

當要顯示一個View就調用一次這個方法。這個方法是ListView性能好壞的關鍵。方法中有個convertView,這個是Android在爲咱們而作的緩存機制。code

ListView中每一個item都是經過getView返回並顯示的,假如item有不少個,那麼重複建立這麼多對象來顯示顯然是不合理。所以,Android提供了Recycler,將沒有正在顯示的item放進RecycleBin,而後在顯示新視圖時從RecycleBin中複用這個View。對象

 

Recycler的工做原理大體以下:圖片

假設屏幕最多能看到11個item,那麼當第1個item滾出屏幕,這個item的View進入RecycleBin中,第12個要出現前,經過getView從回收站(RecycleBin)中重用這個View,而後設置數據,而沒必要從新建立一個View。內存

 

咱們用Android提供的APIDemos來驗證這個過程:ci

 

先看關鍵代碼:

public View getView(int position, View convertView, ViewGroup parent) 
{ 
    // A ViewHolder keeps references to children views to avoid unneccessary calls 
    // to findViewById() on each row. 

    ViewHolder holder; 
    // When convertView is not null, we can reuse it directly, there is no need 
    // to reinflate it. We only inflate a new View when the convertView supplied 
    // by ListView is null. 

    if (convertView == null) 
	{ 
        convertView = mInflater.inflate(R.layout.list_item_icon_text, null); 
        Log.v("tag", "positon "+position+" convertView is null, "+"new: "+convertView); 
        // Creates a ViewHolder and store references to the two children views 
        // we want to bind data to. 
        holder = new ViewHolder(); 
        holder.text = (TextView) convertView.findViewById(R.id.text); 
        holder.icon = (ImageView) convertView.findViewById(R.id.icon); 
        convertView.setTag(holder); 
    } 
	else 
	{ 
        // Get the ViewHolder back to get fast access to the TextView 
        // and the ImageView. 
        holder = (ViewHolder) convertView.getTag(); 
        Log.v("tag", "positon "+position+" convertView is not null, "+convertView); 
    } 

    // Bind the data efficiently with the holder. 
    holder.text.setText(DATA[position]); 
    holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2); 
    return convertView; 
} 
 
static class ViewHolder 
{ 
    TextView text; 
    ImageView icon; 
}

效果圖:

能夠看到,一打開Activity,看到10個item.

咱們看看Log信息:

能夠看出,每次convertView都是null, 都是新建一個View來顯示的。

當咱們向下滑動,以下圖:

因爲item0和item10都顯示一半,因此item10也是新建出來,可是當要顯示item11的時候,因爲item0已經不在屏幕上,因此item11複用了item0的實例。能夠從

如下Log信息看出:

咱們分析Log信息,能夠看出item11的對象是item0,item12的對象是item1,如此類推。

這樣,經過複用convertView,就能夠避免每次都新建View,節省內存並且優化ListView的滑動效果。

 

 

2.  ListView的Layout XML

 

除了上述說的,還有一個要點就是ListView在Layout XML中的描述。

先看問題:

有時,咱們可能會看到一打開ListView,getView會重複調用好次(假設屏幕最多能夠看到6個item),以下圖:

一直重複0-6,  0-5,0-5,0-5,0-5,0-5。並且,convertView一開始都是同一個View,這個是由於ListView的

android:layout_height="wrap_content"。

咱們修改成android:layout_height="fill_parent",Log信息以下:

能夠看出,修改以後ListView的getView調用恢復和Recycler的行爲一致。

至於爲何使用wrap_content會出現重複調用的狀況,我尚未研究過。不過初步以爲是由於在Android描繪ListView的時候,因爲不清楚高度,因此使用一個item去試探ListView在屏幕中的最大高度所引發。但願有知道的朋友可以告訴,先謝謝了!

 

最後,若是上面有什麼地方說錯的話,但願可以指出,互相進步嘛。

相關文章
相關標籤/搜索