Вень ми встановили setHasFixedSize(true)
на RecyclerView
це означає , що переробник - х розмір фіксований і не залежить від вмісту адаптера. І в цьому випадку onLayout
не вимагається використання рециркулятора, коли ми оновлюємо дані адаптера (але є виняток).
Перейдемо до прикладу:
RecyclerView
має RecyclerViewDataObserver
( знайдіть реалізацію за замовчуванням у цьому файлі ) кількома методами, головне важливе:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Цей метод викликається , якщо ми встановлюємо setHasFixedSize(true)
і оновлювати дані закріпних за допомогою: notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved
. У цьому випадку немає дзвінків на переробник onLayout
, але є заклики до requestLayout
оновлення дітей.
Але якщо ми встановимо setHasFixedSize(true)
та оновимо дані адаптера за допомогою notifyItemChanged
цього виклику onChange
за замовчуванням утилізатора RecyclerViewDataObserver
і не дзвонить triggerUpdateProcessor
. У цьому випадку переробник onLayout
викликається, коли ми встановимо setHasFixedSize
true
або 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();
}
}
Як перевірити самостійно:
Створіть власні RecyclerView
та змінити:
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)
}
Встановіть розмір рециркулятора на match_parent
(у xml). Спробуйте оновити дані адаптера за допомогою replaceData
та за replaceOne
допомогою сеансу, setHasFixedSize(true)
а потім 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)
}
І перевірте свій журнал.
Мій журнал:
// 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
Підсумуйте:
Якщо ми встановлюємо setHasFixedSize(true)
та оновлюємо дані адаптера, повідомляючи спостерігача іншим способом, ніж дзвінки notifyDataSetChanged
, то у вас є деяка ефективність, оскільки це не викликає onLayout
метод переробки .