Wen fijamos setHasFixedSize(true)
en RecyclerView
que los medios de tamaño reciclador es fijo y no se ve afectada por el contenido de adaptador. Y en este caso onLayout
no se llama al reciclador cuando actualizamos los datos del adaptador (pero hay una excepción).
Vayamos al ejemplo:
RecyclerView
tiene un RecyclerViewDataObserver
( encontrar implementación predeterminada en este archivo ) con varios métodos, el principal importante es:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Este método se llama si establecemos setHasFixedSize(true)
y actualizar los datos de un adaptador a través de: notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved
. En este caso no hay llamadas al reciclador onLayout
, pero hay llamadas a requestLayout
actualizar niños.
Pero si configuramos setHasFixedSize(true)
y actualizamos los datos de un adaptador a través de, notifyItemChanged
entonces hay una llamada al onChange
valor predeterminado del reciclador RecyclerViewDataObserver
y no hay llamadas a triggerUpdateProcessor
. En este caso, onLayout
se llama al reciclador cada vez que configuramos setHasFixedSize
true
o 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();
}
}
Cómo verificar por ti mismo:
Crear personalizado RecyclerView
y anular:
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)
}
Establezca el tamaño del reciclador en match_parent
(en xml). Intente actualizar los datos del adaptador usando replaceData
y replaceOne
con seting setHasFixedSize(true)
y luego 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)
}
Y revisa tu registro.
Mi registro:
// 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
Resumir:
Si configuramos setHasFixedSize(true)
y actualizamos los datos del adaptador notificando a un observador de otra manera que no sea la llamada notifyDataSetChanged
, entonces tiene un poco de rendimiento, porque no hay llamadas al onLayout
método de reciclador .