Wen nous avons mis setHasFixedSize(true)
sur RecyclerView
ce que les moyens de taille recycleur est fixe et n'est pas affectée par le contenu de l' adaptateur. Et dans ce cas, il onLayout
n'est pas appelé sur recycleur lorsque nous mettons à jour les données de l'adaptateur (mais il y a une exception).
Passons à l'exemple:
RecyclerView
a une RecyclerViewDataObserver
( trouver l'implemntation par défaut dans ce fichier ) avec plusieurs méthodes, la principale importante est:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Cette méthode est appelée si nous fixons setHasFixedSize(true)
et mettre à jour les données d'un adaptateur via: notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved
. Dans ce cas, il n'y a pas d'appels au recycleur onLayout
, mais il y a des appels à requestLayout
pour mettre à jour les enfants.
Mais si nous définissons setHasFixedSize(true)
et mettons à jour les données d'un adaptateur via, notifyItemChanged
il y a un appel à onChange
la valeur par défaut du recycleur RecyclerViewDataObserver
et aucun appel à triggerUpdateProcessor
. Dans ce cas, le recycleur onLayout
est appelé chaque fois que nous définissons setHasFixedSize
true
ou 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();
}
}
Comment vérifier par vous-même:
Créer une personnalisation RecyclerView
et remplacer:
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)
}
Définissez la taille du recycleur sur match_parent
(en xml). Essayez de mettre à jour les données de l'adaptateur en utilisant replaceData
et replaceOne
avec la configuration setHasFixedSize(true)
, puis 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)
}
Et vérifiez votre journal.
Mon journal:
// 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
Résumer:
Si nous définissons setHasFixedSize(true)
et mettons à jour les données de l'adaptateur en notifiant un observateur d'une autre manière que l'appel notifyDataSetChanged
, alors vous avez des performances, car il n'y a pas d'appels à la onLayout
méthode de recyclage .