Android ListView源碼學習

來源:互聯網
上載者:User

             最近研究瀑布流代碼,順便學習了下ListView的源碼。這裡記錄下。

        ListView源碼裡已經對ListView的效能進行了極大化的最佳化,這裡主要用到了資源回收筒(RecycleBin)這麼個東西。

RecycleBin促進布局視圖的重用,資源回收筒有兩個層級的儲存:ActiveViews和ScrapViews。ActiveViews是指那些布局開始顯示在螢幕上的Views,它們顯示當前資訊。在布局的底部,所有ActiveViews被降級為ScrapViews。ScrapViews是指那些有可能被Adapter使用以避免重複分配的view。就是說資源回收筒維持著一個序列化的集合,這個集合裡的view可能要比一個螢幕能顯示的view的個數稍微多些。當listview滑動時,一些不可見的ActiveViews將會被降級到ScrapViews。

       下面將一條重要的調用路線記錄下。onLayout------->layoutChildren---------->fillFromTop---------->fillDown------->

makeAndAddView------->obtainView.反過來記錄下每個函數的具體細節。

        obtainView.這個方法是用來擷取一個view然後讓它帶著資料在特定的位置顯示。當我們發現這個view在資源回收筒不可用時我們調用這個方法,這時候我們唯一的選擇就是轉換一箇舊的view或者建立一個新的view。貼上代碼如下。

View obtainView(int position, boolean[] isScrap) {isScrap[0] = false;View scrapView;scrapView = mRecycler.getScrapView(position);View child;if (scrapView != null) {if (ViewDebug.TRACE_RECYCLER) {ViewDebug.trace(scrapView, ViewDebug.RecyclerTraceType.RECYCLE_FROM_SCRAP_HEAP,position, -1);}child = mAdapter.getView(position, scrapView, this);if (ViewDebug.TRACE_RECYCLER) {ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW,position, getChildCount());}if (child != scrapView) {mRecycler.addScrapView(scrapView);if (mCacheColorHint != 0) {child.setDrawingCacheBackgroundColor(mCacheColorHint);}if (ViewDebug.TRACE_RECYCLER) {ViewDebug.trace(scrapView, ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,position, -1);}} else {isScrap[0] = true;//child.dispatchFinishTemporaryDetach();dispatchFinishTemporaryDetach(child);}} else {child = mAdapter.getView(position, null, this);if (mCacheColorHint != 0) {child.setDrawingCacheBackgroundColor(mCacheColorHint);}if (ViewDebug.TRACE_RECYCLER) {ViewDebug.trace(child, ViewDebug.RecyclerTraceType.NEW_VIEW,position, getChildCount());}}return child;}

第一次走肯定會走到else條件裡去。所以child = mAdapter.getView(position, null, this);所以在我們的Adapter裡convertView傳入的是null,這時候需要我們的adapter inflate 我們的listview  item layout。

當scrapView不為null時,就會複用view而不會再建立,從而最佳化了listview。在crapView = mRecycler.getScrapView(position);我們追蹤getScrapView的代碼發現,ScrapView其實是無序的,如果listview

的type只有一種的話,這個position是沒有任何意義的。看下代碼。

View getScrapView(int position) {ArrayList<View> scrapViews;if (mViewTypeCount == 1) {scrapViews = mCurrentScrap;int size = scrapViews.size();if (size > 0) {return scrapViews.remove(size - 1);} else {return null;}} else {int whichScrap = mAdapter.getItemViewType(position);if (whichScrap >= 0 && whichScrap < mScrapViews.length) {scrapViews = mScrapViews[whichScrap];int size = scrapViews.size();if (size > 0) {return scrapViews.remove(size - 1);}}}return null;}
scrapViews 什麼時候被初始化或者賦值的哪?在layoutChildren裡執行的:recycleBin.scrapActiveViews();
這個方法將activeview降級為scrapview。

         makeAndAddView 取得View並把它添加到我們的子視圖列表裡。這個View可以是新的,或者是從未使用的View轉換以及從資源回收筒拿過來的。

private View makeAndAddView(int position, int childrenBottomOrTop, boolean flow,boolean selected) {View child;int childrenLeft;if (!mDataChanged) {// Try to use an exsiting view for this positionchild = mRecycler.getActiveView(position);if (child != null) {if (ViewDebug.TRACE_RECYCLER) {ViewDebug.trace(child, ViewDebug.RecyclerTraceType.RECYCLE_FROM_ACTIVE_HEAP,position, getChildCount());}// Found it -- we're using an existing child// This just needs to be positionedchildrenLeft = getItemLeft(position);setupChild(child, position, childrenBottomOrTop, flow, childrenLeft, selected, true);return child;}}//Notify new item is added to view.onItemAddedToList( position, flow );//擷取開始繪製時距離左邊螢幕邊框的距離childrenLeft = getItemLeft( position );// Make a new view for this position, or convert an unused view if possiblechild = obtainView(position, mIsScrap);// This needs to be positioned and measuredsetupChild(child, position, childrenBottomOrTop, flow, childrenLeft, selected, mIsScrap[0]);return child;}

如果資料沒有發生改變,我們直接從資源回收筒的ActiveView裡拿出那個位置的View,擷取這個View的左邊距,然後

setupChild(child, position, childrenBottomOrTop, flow, childrenLeft, selected, true);

如果資料是新添加或者發生變化,我們需要調用obtainView來擷取child。

setupChild 這個方法主要是確保這個子View被測定並且處於合適的位置。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.