如何正確使用RecyclerView的setHasFixedSize方法提高布局計(jì)算性能
setHasFixedSize
setHasFixedSize(boolean hasFixedSize) 是 Android 中 RecyclerView 類的一個(gè)方法,用于設(shè)置 RecyclerView 是否具有固定大小。
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;
}翻譯一下注釋如下:
如果RecyclerView能夠提前知道RecyclerView的大小不受適配器內(nèi)容的影響,可以執(zhí)行幾個(gè)優(yōu)化。RecyclerView仍然可以根據(jù)其他因素(例如其父項(xiàng)的大?。└钠浯笮。舜笮∮?jì)算不能取決于其子項(xiàng)的大小或適配器的內(nèi)容(適配器中的項(xiàng)目數(shù)除外) 如果您對(duì)RecyclerView的使用屬于此類別,請(qǐng)將其設(shè)置為{@code true}。它將允許RecyclerView避免在適配器內(nèi)容更改時(shí)使整個(gè)布局無效。
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
    if (mLayout == null) {
        defaultOnMeasure(widthSpec, heightSpec);
        return;
    }
    if (mLayout.isAutoMeasureEnabled()) {
        //....... 省略部分代碼
    } else {
        if (mHasFixedSize) {
            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
            return;
        }
        // custom onMeasure
        //......  省略部分代碼
        if (mAdapter != null) {
            mState.mItemCount = mAdapter.getItemCount();
        } else {
            mState.mItemCount = 0;
        }
        startInterceptRequestLayout();
        mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
        stopInterceptRequestLayout(false);
        mState.mInPreLayout = false; // clear
    }
}由上面內(nèi)容可知:調(diào)用 setHasFixedSize(true) 時(shí),RecyclerView 的子項(xiàng)(items)的大小不會(huì)改變,即使添加或移除了 RecyclerView 中的項(xiàng),RecyclerView 也不會(huì)重新測(cè)量和布局它的所有子項(xiàng)。好處是可以提高性能(測(cè)量和布局是一個(gè)相對(duì)耗時(shí)的操作)。
重要的是要確保RecyclerView 實(shí)際上具有固定大小。如果 RecyclerView 的子項(xiàng)大小可能會(huì)改變(例如,由于文本長(zhǎng)度的變化或圖像加載),應(yīng)該調(diào)用 setHasFixedSize(false)。當(dāng)子項(xiàng)大小改變時(shí),RecyclerView 會(huì)重新測(cè)量和布局它們確保能正確顯示。
如果你設(shè)置 hasFixedSize(true),但在運(yùn)行時(shí) RecyclerView 的大小實(shí)際上發(fā)生了變化(例如,因?yàn)槠鋬?nèi)容或布局參數(shù)的變化),那么 RecyclerView 的布局可能不會(huì)正確地更新,可能會(huì)導(dǎo)致顯示問題。
總結(jié)
在確定 RecyclerView 的大小在整個(gè)生命周期中都不會(huì)改變時(shí),才將 hasFixedSize() 設(shè)置為 true。如果不確定,或者 RecyclerView 的大小可能會(huì)改變,應(yīng)該將其設(shè)置為 false,確保 RecyclerView 能夠正確地重新計(jì)算其布局。
- 使用固定的寬度/高度(可以用setHasFixedSize(true)):
 
<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:overScrollMode="never"
    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
    app:spanCount="2" />- 不使用固定的寬度/高度:應(yīng)該使用setHasFixedSize(false),因?yàn)閷挾然蚋叨瓤梢愿淖僐ecyclerView的大小。
 
<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:overScrollMode="never"
    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
    app:spanCount="2" />即使將 hasFixedSize() 設(shè)置為 true,RecyclerView 仍然會(huì)監(jiān)聽滾動(dòng)事件,滾動(dòng)性能不會(huì)受到影響,主要影響的是布局計(jì)算的性能。















 
 
 

 
 
 
 