Wen wir setzen setHasFixedSize(true)
auf , RecyclerView
dass Mittel Recycler eine feste Größe ist und nicht durch den Adapter Inhalt betroffen. In diesem Fall onLayout
wird der Recycler nicht aufgerufen, wenn die Daten des Adapters aktualisiert werden (es gibt jedoch eine Ausnahme).
Gehen wir zum Beispiel:
RecyclerView
hat eine RecyclerViewDataObserver
( Standardimplementierung in dieser Datei finden ) mit mehreren Methoden, die wichtigste ist:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Diese Methode wird aufgerufen, wenn wir setHasFixedSize(true)
die Daten eines Adapters über Folgendes festlegen und aktualisieren : notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved
. In diesem Fall gibt es keine Anrufe beim Recycler onLayout
, aber Anrufe requestLayout
beim Aktualisieren von Kindern.
Wenn wir jedoch setHasFixedSize(true)
die Daten eines Adapters über einstellen und aktualisieren, notifyItemChanged
wird onChange
die Standardeinstellung des Recyclers aufgerufen RecyclerViewDataObserver
und keine aufgerufen triggerUpdateProcessor
. In diesem Fall wird der Recycler onLayout
immer dann aufgerufen, wenn wir setHasFixedSize
true
oder einstellen 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();
}
}
So überprüfen Sie selbst:
Benutzerdefiniert erstellen RecyclerView
und überschreiben:
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)
}
Stellen Sie die Größe des Recyclers auf match_parent
(in xml). Versuchen Sie, die Daten des Adapters mit replaceData
und replaceOne
mit der Einstellung setHasFixedSize(true)
und dann zu aktualisieren 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)
}
Und überprüfen Sie Ihr Protokoll.
Mein Log:
// 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
Zusammenfassen:
Wenn wir die Adapterdaten so einstellen setHasFixedSize(true)
und aktualisieren, dass ein Beobachter auf eine andere Weise als durch Aufrufen benachrichtigt wird notifyDataSetChanged
, haben Sie eine gewisse Leistung, da dies keine Aufrufe der Recycler- onLayout
Methode sind.