如何正确使用RecyclerView的setHasFixedSize方法提高布局计算性能

移动开发 Android
在确定 RecyclerView​ 的大小在整个生命周期中都不会改变时,才将 hasFixedSize()​ 设置为 true。如果不确定,或者 RecyclerView​ 的大小可能会改变,应该将其设置为 false,确保 RecyclerView 能够正确地重新计算其布局。

setHasFixedSize

setHasFixedSize(boolean hasFixedSize) 是 Android 中 RecyclerView 类的一个方法,用于设置 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的大小不受适配器内容的影响,可以执行几个优化。RecyclerView仍然可以根据其他因素(例如其父项的大小)更改其大小,但此大小计算不能取决于其子项的大小或适配器的内容(适配器中的项目数除外) 如果您对RecyclerView的使用属于此类别,请将其设置为{@code true}。它将允许RecyclerView避免在适配器内容更改时使整个布局无效。

@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
    }
}

由上面内容可知:调用 setHasFixedSize(true) 时,RecyclerView 的子项(items)的大小不会改变,即使添加或移除了 RecyclerView 中的项,RecyclerView 也不会重新测量和布局它的所有子项。好处是可以提高性能(测量和布局是一个相对耗时的操作)。

重要的是要确保RecyclerView 实际上具有固定大小。如果 RecyclerView 的子项大小可能会改变(例如,由于文本长度的变化或图像加载),应该调用 setHasFixedSize(false)。当子项大小改变时,RecyclerView 会重新测量和布局它们确保能正确显示。

如果你设置 hasFixedSize(true),但在运行时 RecyclerView 的大小实际上发生了变化(例如,因为其内容或布局参数的变化),那么 RecyclerView 的布局可能不会正确地更新,可能会导致显示问题。

总结

在确定 RecyclerView 的大小在整个生命周期中都不会改变时,才将 hasFixedSize() 设置为 true。如果不确定,或者 RecyclerView 的大小可能会改变,应该将其设置为 false,确保 RecyclerView 能够正确地重新计算其布局。

  1. 使用固定的宽度/高度(可以用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" />
  1. 不使用固定的宽度/高度:应该使用setHasFixedSize(false),因为宽度或高度可以改变RecyclerView的大小。
<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() 设置为 true,RecyclerView 仍然会监听滚动事件,滚动性能不会受到影响,主要影响的是布局计算的性能。

责任编辑:武晓燕 来源: 沐雨花飞蝶
相关推荐

2016-09-22 09:24:33

AndroidViewStub

2013-01-08 16:05:23

Android开发布局ViewStub

2017-07-10 13:09:45

前端Flexbox

2011-05-24 15:15:12

mysql性能

2019-03-05 10:20:49

WebWebpack分离数据

2011-04-27 16:38:31

投影机

2009-12-31 15:21:48

Silverlight

2009-11-02 14:08:05

2021-07-14 14:06:06

CSS前端浏览器

2011-04-11 14:56:09

Oracle性能

2010-01-05 18:49:57

.NET Framew

2009-08-06 11:12:17

提高GDI编程性能

2021-11-05 11:03:33

云计算开发技术

2015-10-10 11:00:05

RubyRails性能

2015-11-16 10:21:28

Java中锁性能

2023-08-18 14:10:00

CDN数据中心

2015-10-14 17:27:18

性能

2010-07-29 10:19:18

提高DB2 IMPOR

2015-03-18 09:59:14

CSSCSS提高渲染性

2022-09-27 15:13:38

边缘计算
点赞
收藏

51CTO技术栈公众号