Se impostato setHasFixedSize(true)
, RecyclerView
significa che le dimensioni del riciclatore sono fisse e non sono influenzate dal contenuto dell'adattatore. E in questo caso onLayout
non viene chiamato il riciclatore quando aggiorniamo i dati dell'adattatore (ma c'è un'eccezione).
Andiamo all'esempio:
RecyclerView
ha un RecyclerViewDataObserver
( trova implementazione predefinita in questo file ) con diversi metodi, il principale importante è:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Questo metodo viene chiamato se abbiamo impostato setHasFixedSize(true)
e aggiornare i dati di un adattatore tramite: notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved
. In questo caso non ci sono chiamate al riciclatore onLayout
, ma ci sono chiamate requestLayout
per l'aggiornamento dei bambini.
Ma se impostiamo setHasFixedSize(true)
e aggiorniamo i dati di un adattatore tramite notifyItemChanged
allora c'è una chiamata al onChange
valore predefinito del riciclatore RecyclerViewDataObserver
e nessuna chiamata a triggerUpdateProcessor
. In questo caso il riciclatore onLayout
viene chiamato ogni volta che impostiamo 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();
}
}
Come controllare da soli:
Crea personalizzato RecyclerView
e sostituisci:
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)
}
Impostare la dimensione del riciclatore su match_parent
(in xml). Prova ad aggiornare i dati dell'adattatore utilizzando replaceData
e replaceOne
con l'impostazione setHasFixedSize(true)
e quindi 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)
}
E controlla il tuo registro.
Il mio 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
Ricapitolare:
Se impostiamo setHasFixedSize(true)
e aggiorniamo i dati dell'adattatore con la notifica a un osservatore in qualche modo diverso dalla chiamata notifyDataSetChanged
, allora hai delle prestazioni, perché non si tratta di chiamate al onLayout
metodo del riciclatore .