Wen kita set setHasFixedSize(true)
pada RecyclerView
yang berarti ukuran pendaur ulang adalah tetap dan tidak terpengaruh oleh isi adaptor. Dan dalam hal onLayout
ini tidak dipanggil pada pendaur ulang saat kita memperbarui data adaptor (tapi ada pengecualian).
Mari kita lihat contoh:
RecyclerView
memiliki 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 requestLayout
untuk memperbarui turunannya.
Tetapi jika kita mengatur setHasFixedSize(true)
dan memperbarui data adaptor melalui notifyItemChanged
maka ada panggilan ke onChange
default pendaur ulang RecyclerViewDataObserver
dan tidak ada panggilan ke triggerUpdateProcessor
. Dalam hal ini pendaur ulang onLayout
dipanggil setiap kali kita menyetel setHasFixedSize
true
atau 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 RecyclerView
dan 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 replaceData
dan 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 onLayout
metode pendaur ulang .