ListView的複用和快取機制

weixin_34402408發表於2016-07-18

複用分析

**1. 在AbListView中 **

/**
 * The data set used to store unused views that should be reused during the next layout
 * to avoid creating new ones
 */
final RecycleBin mRecycler = new RecycleBin();

RecycleBin包含了兩個級別的儲存,ActiveViews和ScrapViews,ActiveViews儲存的是第一次顯示在螢幕上的View;所有的ActiveViews最終都會被移到ScrapViews,ScrapViews儲存的是有可能被adapter複用的View。

**2. 在ListView的LayoutChildren 中 **

@Override
protected void layoutChildren() 
{
    if (dataChanged) 
    {
        for (int i = 0; i < childCount; i++) 
        {
            recycleBin.addScrapView(getChildAt(i));   
        }
    } else 
    {
        recycleBin.fillActiveViews(childCount, firstPosition);
    }
    ....
}

可以看出,如果資料發生變化則把當前的ItemView放入ScrapViews中,否則把當前顯示的ItemView放入ActiveViews中。

3. 那麼我們們關鍵的getView方法到底是在哪呼叫呢
在AbsListView中我們看obtainView中的方法:

/**
 * Get a view and have it show the data associated with the specified
 * position. This is called when we have already discovered that the view is
 * not available for reuse in the recycle bin. The only choices left are
 * converting an old view or making a new one.
 *
 * @param position The position to display
 * @param isScrap Array of at least 1 boolean, the first entry will become true if
 *                the returned view was taken from the scrap heap, false if otherwise.
 * 
 * @return A view displaying the data associated with the specified position
 */
View obtainView(int position, boolean[] isScrap) 
{
    final View scrapView = mRecycler.getScrapView(position);
    final View child = mAdapter.getView(position, scrapView, this);
    if (scrapView != null) {
        if (child != scrapView) {
            // Failed to re-bind the data, return scrap to the heap.
            mRecycler.addScrapView(scrapView, position);
        } else {
            isScrap[0] = true;

            child.dispatchFinishTemporaryDetach();
        }
    }

    return child;
}

可以看到,這個方法就是返回當前一個佈局使用者當前Item的顯示,首先根據position去ScrapView中找,找到後呼叫我們的getView,此時getView裡面的convertView!=null了,然後getView如果返回的View發生變化,快取下來,否則convertView==null了。

參考資料

相關文章