SIr*_*lot 120 android android-5.0-lollipop android-recyclerview
我理解起来有些困难setHasFixedSize().我知道,当RecyclerView文档中的大小不变时,它用于优化.
这意味着什么?在大多数常见情况下,ListView几乎总是具有固定的大小.在什么情况下它不是固定的大小?这是否意味着它在屏幕上占据的实际房地产随着内容的增长而增长?
Luk*_*iko 101
RecyclerView的一个非常简化的版本有:
void onItemsInsertedOrRemoved() {
if (hasFixedSize) layoutChildren();
else requestLayout();
}
Run Code Online (Sandbox Code Playgroud)
此链接描述了为什么呼叫requestLayout可能很昂贵.基本上每当插入,移动或移除项目时,RecyclerView的大小(宽度和高度)可能会发生变化,反过来,视图层次结构中任何其他视图的大小也可能会发生变化.如果经常添加或删除项目,这尤其麻烦.
setHasFixedSize当更改适配器的内容不改变其高度或宽度时,通过设置为true 避免不必要的布局传递.
更新: JavaDoc已更新,以更好地描述方法实际执行的操作.
如果RecyclerView可以提前知道RecyclerView的大小不受适配器内容的影响,则可以执行多项优化.RecyclerView仍然可以根据其他因素(例如其父级的大小)更改其大小,但此大小计算不能取决于其子级的大小或其适配器的内容(除了适配器中的项目数).
如果您使用RecyclerView属于此类别,请将其设置为{@code true}.它允许RecyclerView在其适配器内容发生变化时避免使整个布局无效.
@param hasFixedSize如果适配器更改不能影响RecyclerView的大小,则为true.
Kev*_*vin 20
可以确认setHasFixedSize与RecyclerView本身有关,而不是每个项目的大小适应它.
您现在可以android:layout_height="wrap_content"在RecyclerView上使用,除其他外,它允许CollapsingToolbarLayout知道它在RecyclerView为空时不应该崩溃.这仅适用setHasFixedSize(false)于在RecylcerView上使用的情况.
如果setHasFixedSize(true)在RecyclerView上使用,则此行为可防止CollapsingToolbarLayout崩溃,即使RecyclerView确实为空,也不起作用.
如果setHasFixedSize与物品的大小有关,则当RecyclerView没有物品时,它应该没有任何效果.
Gas*_*lén 18
如果我们有一个RecyclerViewwith match_parentas height/width,我们应该添加,setHasFixedSize(true)因为RecyclerView它本身的大小不会改变向其中插入或删除项目。
setHasFixedSize如果我们有一个高度/宽度wrap_content为高度/宽度的 RecyclerView 应该是假的,因为适配器插入的每个元素都可以Recycler根据插入/删除的项目改变 的大小,因此,Recycler每次我们添加/删除的大小都会不同项目。
更清楚地说,如果我们使用
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Run Code Online (Sandbox Code Playgroud)
我们可以用 my_recycler_view.setHasFixedSize(true)
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Run Code Online (Sandbox Code Playgroud)
那么,我们应该使用my_recycler_view.setHasFixedSize(false),如果我们使用wrap_content的宽度或高度在我们的RecyclerView
dan*_*mit 12
ListView有一个类似的命名函数,我认为它确实反映了有关各个列表项高度大小的信息.RecyclerView的文档非常清楚地表明它指的是RecyclerView本身的大小,而不是其项目的大小.
从上面的setHasFixedSize()方法的RecyclerView源注释中:
* RecyclerView can perform several optimizations if it can know in advance that changes in
* adapter content cannot change the size of the RecyclerView itself.
* If your use of RecyclerView falls into this category, set this to true.
Run Code Online (Sandbox Code Playgroud)
当我们设置setHasFixedSize(true)时RecyclerView,意味着回收者的大小是固定的,不受适配器内容的影响。在这种情况下onLayout,当我们更新适配器的数据时不会在回收器上调用(但有一个例外)。
我们来看例子:
RecyclerView有一个RecyclerViewDataObserver(在这个文件中找到默认实现)有几种方法,主要重要的是:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们通过以下方式设置setHasFixedSize(true)和更新适配器的数据,则会调用此方法:notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved。在这种情况下,没有调用回收者的onLayout,但有requestLayout更新子代的调用。
但是,如果我们通过设置setHasFixedSize(true)和更新适配器的数据notifyItemChanged,则会调用onChange回收器的默认值,RecyclerViewDataObserver而不会调用triggerUpdateProcessor. 在这种情况下,onLayout只要我们设置setHasFixedSize true或,就会调用回收器false。
// no calls to triggerUpdateProcessor
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
processDataSetCompletelyChanged(true);
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
// calls to triggerUpdateProcessor
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
triggerUpdateProcessor();
}
}
Run Code Online (Sandbox Code Playgroud)
如何自行检查:
创建自定义RecyclerView和覆盖:
override fun requestLayout() {
Log.d("CustomRecycler", "requestLayout is called")
super.requestLayout()
}
override fun invalidate() {
Log.d("CustomRecycler", "invalidate is called")
super.invalidate()
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
Log.d("CustomRecycler", "onLayout is called")
super.onLayout(changed, l, t, r, b)
}
Run Code Online (Sandbox Code Playgroud)
将回收器大小设置为match_parent(以 xml 格式)。尝试使用适配器的数据更新replaceData,并replaceOne 与塞汀setHasFixedSize(true)然后false。
// onLayout is called every time
fun replaceAll(data: List<String>) {
dataSet.clear()
dataSet.addAll(data)
this.notifyDataSetChanged()
}
// onLayout is called only for setHasFixedSize(false)
fun replaceOne(data: List<String>) {
dataSet.removeAt(0)
dataSet.addAll(0, data[0])
this.notifyItemChanged(0)
}
Run Code Online (Sandbox Code Playgroud)
并检查您的日志。
我的日志:
// for replaceAll
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onMeasure is called
D/CustomRecycler: onMeasure is called
D/CustomRecycler: onLayout
D/CustomRecycler: requestLayout is called
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called
// for replaceOne
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called
Run Code Online (Sandbox Code Playgroud)
总结:
如果我们setHasFixedSize(true)通过调用以外的其他方式通知观察者来设置和更新适配器的数据notifyDataSetChanged,那么您将获得一些性能,因为没有调用回收器onLayout方法。
| 归档时间: |
|
| 查看次数: |
64370 次 |
| 最近记录: |