歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

探究Android ListView 的緩存機制

概述

ListView 是繼承AbListView,AbListView是所有列表類控件的基類。

ListView的數據加載

在ListView數據加載中最關鍵的一個函數就是makeAndAddView(),這個函數的作用就獲得一個ChildView並把該ChildView添加到List中,具體見源碼分析:

private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
        boolean selected) {
    View child;//即ChildView

	//如果數據沒有發生改變
    if (!mDataChanged) {
        //優先從循環器中獲取該位置的視圖
        // Try to use an existing view for this position
        child = mRecycler.getActiveView(position);
        if (child != null) {
            // Found it -- we're using an existing child
            //如果找到了就直接添加到List中
            // This just needs to be positioned
            setupChild(child, position, y, flow, childrenLeft, selected, true);

            return child;
        }
    }

	//如果數據發生了改變,則在該位置上新建一個視圖,或者如果可能的話轉換一個已經沒有用的視圖(可能是當整個ListView其他位置發生了變化,但是該位置的ChildView並未發生任何變化)
    // Make a new view for this position, or convert an unused view if possible
    child = obtainView(position, mIsScrap);

    // This needs to be positioned and measured
    setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);

	//返回該childView
    return child;
}

ListView的緩存機制

當ListView發生滑動操作時,若干已經加載的ChildView會被因滑動而被暫時隱藏掉,為了避免下次顯示再重新加載,這時ListView的緩存機制就會被觸發,即運行layoutChildren()函數(其實任何觸碰事件都會觸發,即onTouchEvent() -。-)。

那麼ListView的緩存機制是依靠什麼來緩存的呢?答案就是AbListView中 的內部類RecycleBin。關於RecycleBin的具體作用,源碼中的注釋已經解釋的非常清楚了,在此就不在贅述。

 /**
 * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of
 * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the
 * start of a layout. By construction, they are displaying current information. At the end of
 * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that
 * could potentially be used by the adapter to avoid allocating views unnecessarily.
 *... ...
 */

當需要緩存ActiveViews時會調用fillActiveViews()函數,該函數會把ListView中的所有ActiveViews 一次性都緩存起來。

	/**
     * Fill ActiveViews with all of the children of the AbsListView.
     * ... ...
     */
    void fillActiveViews(int childCount, int firstActivePosition) {
        if (mActiveViews.length < childCount) {
            mActiveViews = new View[childCount];
        }
        mFirstActivePosition = firstActivePosition;

        //noinspection MismatchedReadAndWriteOfArray
        final View[] activeViews = mActiveViews;
		... ...
    }

而對於ScrapViews則是調用的addScrapView()函數。

	/**
     * Puts a view into the list of scrap views.
     * <p>
     * If the list data hasn't changed or the adapter has stable IDs, views
     * with transient state will be preserved for later retrieval.
     *
     * @param scrap The view to add
     * @param position The view's position within its parent
     */
    void addScrapView(View scrap, int position) {
    ... ...
    // Don't scrap views that have transient state.
        final boolean scrapHasTransientState = scrap.hasTransientState();
        if (scrapHasTransientState) {
        //Transient狀態
		... ...
		}else{
		//scrap狀態
		... ...
		}
		... ...
    }
    

該函數中又分為兩個不同的level,一個是transient瞬時態,另一個就是一般的普通態,關於這兩個狀態的區分我個人的想法是為了更加快速的獲取ScrapViews,因為處於瞬時狀態的view最有可能是接下來將要在界面上顯示的View,畢竟你向上或向下滑動列表時目的就是這個,這一點在obtainView()函數中得到了體現:

View obtainView(int position, boolean[] isScrap) {
... ...
//優先獲取TransientStateView
scrapView = mRecycler.getTransientStateView(position);
    if (scrapView == null) {
        scrapView = mRecycler.getScrapView(position);
    }
... ...
}

還有一個比較重要的函數就是scrapActiveViews()函數,它的作用是將目前所有的ActiveViews降級為ScrapViews,並將之前的所有ScrapViews清除。該函數在每次調用layoutChildern()函數時必定會被調用執行,目的就是為清空所有當前的ActiveViews,為新產生的ActiveViews做好准備。

    /**
     * Move all views remaining in mActiveViews to mScrapViews.
     */
    void scrapActiveViews() {
    ... ...
    //該函數確保mScrapViews的大小不會超過mActiveViews
    pruneScrapViews();
    }

結語

以上是閱讀了ListView以及AbListView源碼後的一些心得總結,畢竟閱讀Android源碼也才剛剛起步,還有很多地方理解的不是很透徹,上文若有理解不當之處歡迎各位指正。

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved