Wen kita set setHasFixedSize(true)pada RecyclerViewyang berarti ukuran pendaur ulang adalah tetap dan tidak terpengaruh oleh isi adaptor. Dan dalam hal onLayoutini tidak dipanggil pada pendaur ulang saat kita memperbarui data adaptor (tapi ada pengecualian).
Mari kita lihat contoh:
RecyclerViewmemiliki RecyclerViewDataObserver( temukan implementasi default di file ini ) dengan beberapa metode, yang terpenting adalah:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Metode ini disebut jika kita mengatur setHasFixedSize(true)dan memperbarui data adaptor ini melalui: notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved. Dalam hal ini tidak ada panggilan ke pendaur ulang onLayout, tetapi ada panggilan ke requestLayoutuntuk memperbarui turunannya.
Tetapi jika kita mengatur setHasFixedSize(true)dan memperbarui data adaptor melalui notifyItemChangedmaka ada panggilan ke onChangedefault pendaur ulang RecyclerViewDataObserverdan tidak ada panggilan ke triggerUpdateProcessor. Dalam hal ini pendaur ulang onLayoutdipanggil setiap kali kita menyetel setHasFixedSize trueatau false.
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
processDataSetCompletelyChanged(true);
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
triggerUpdateProcessor();
}
}
Cara memeriksanya sendiri:
Buat kustom RecyclerViewdan timpa:
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)
}
Setel ukuran pendaur ulang ke match_parent(dalam xml). Coba perbarui data adaptor menggunakan replaceDatadan replaceOne dengan pengaturan setHasFixedSize(true)lalu false.
fun replaceAll(data: List<String>) {
dataSet.clear()
dataSet.addAll(data)
this.notifyDataSetChanged()
}
fun replaceOne(data: List<String>) {
dataSet.removeAt(0)
dataSet.addAll(0, data[0])
this.notifyItemChanged(0)
}
Dan periksa log Anda.
Log saya:
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
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called
Meringkaskan:
Jika kita menyetel setHasFixedSize(true)dan memperbarui data adaptor dengan memberi tahu pengamat dengan cara lain selain memanggil notifyDataSetChanged, maka Anda memiliki kinerja, karena tidak ada panggilan ke onLayoutmetode pendaur ulang .