RecyclerView性能優化:setHasFixedSize


 /** 
     * RecyclerView can perform several optimizations if it can know in advance that RecyclerView's 
     * size is not affected by the adapter contents. RecyclerView can still change its size based 
     * on other factors (e.g. its parent's size) but this size calculation cannot depend on the 
     * size of its children or contents of its adapter (except the number of items in the adapter). 
     * <p> 
     * If your use of RecyclerView falls into this category, set this to {@code true}. It will allow 
     * RecyclerView to avoid invalidating the whole layout when its adapter contents change. 
     * 
     * @param hasFixedSize true if adapter changes cannot affect the size of the RecyclerView. 
     */  
    public void setHasFixedSize(boolean hasFixedSize) {  
        mHasFixedSize = hasFixedSize;  
    }

注釋翻譯:
當知道Adapter內Item的改變不會影響RecyclerView寬高的時候,可以設置為true讓RecyclerView避免重新計算大小。
注意:

當setHasFixedSize為true時,再調用notifyDataSetChanged(),發現大小還是重新計算了,看來理解出現錯誤了。

解答
首先是onMeasure里用到,這個和自定義LayoutManager相關,先不管它。然后是triggerUpdateProcessor()方法用到了,請看源碼:

void triggerUpdateProcessor() {  
            if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {  
                ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);  
            } else {  
                mAdapterUpdateDuringMeasure = true;  
                requestLayout();  
            }  
        }

然后看一下triggerUpdateProcessor()方法被哪些調用法:

onItemRangeChanged()
onItemRangeInserted()
onItemRangeRemoved()
onItemRangeMoved()
這樣看就很明白了,當調用Adapter的增刪改插方法,最后就會根據mHasFixedSize這個值來判斷需要不需要requestLayout();所以這4個方法不會重新繪制。
那我們再來看一下notifyDataSetChanged()執行的代碼,最后是調用了onChanged,調用了requestLayout(),會去重新測量寬高,所以這也是為什么我們設置為true時,大小還是重新計算了的原因。

@Override  
public void onChanged() {  
    assertNotInLayoutOrScroll(null);  
    mState.mStructureChanged = true;  
  
    setDataSetChangedAfterLayout();  
    if (!mAdapterHelper.hasPendingUpdates()) {  
        requestLayout();  
    }  
} 

總結
當我們確定Item的改變不會影響RecyclerView的寬高的時候可以設置setHasFixedSize(true),並通過Adapter的增刪改插方法去刷新RecyclerView,而不是通過notifyDataSetChanged()。(其實可以直接設置為true,當需要改變寬高的時候就用notifyDataSetChanged()去整體刷新一下)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM