Chúng tôi đặt setHasFixedSize(true)
trên RecyclerView
điều đó có nghĩa là kích thước của bộ tái chế được cố định và không bị ảnh hưởng bởi nội dung của bộ chuyển đổi. Và trong trường hợp onLayout
này không được gọi trên bộ tái chế khi chúng tôi cập nhật dữ liệu của bộ điều hợp (nhưng có một ngoại lệ).
Hãy xem ví dụ:
RecyclerView
có một RecyclerViewDataObserver
( tìm ẩn ý mặc định trong tệp này ) với một số phương thức, quan trọng chính là:
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
Phương pháp này được gọi nếu chúng ta thiết lập setHasFixedSize(true)
và cập nhật dữ liệu của bộ điều hợp thông qua : notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved
. Trong trường hợp này, không có cuộc gọi nào đến người tái chế onLayout
, nhưng có cuộc gọi để requestLayout
cập nhật trẻ em.
Nhưng nếu chúng ta thiết lập setHasFixedSize(true)
và cập nhật dữ liệu của bộ điều hợp thông qua notifyItemChanged
thì sẽ có cuộc gọi đến onChange
mặc định của người tái chế RecyclerViewDataObserver
và không có cuộc gọi nào triggerUpdateProcessor
. Trong trường hợp này, trình tái chế onLayout
được gọi bất cứ khi nào chúng ta đặt setHasFixedSize
true
hoặc 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();
}
}
Cách tự kiểm tra:
Tạo tùy chỉnh RecyclerView
và ghi đè:
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)
}
Đặt kích thước của trình tái chế thành match_parent
(tính bằng xml). Cố gắng cập nhật dữ liệu của bộ điều hợp bằng cách sử dụng replaceData
và replaceOne
với thiết lập setHasFixedSize(true)
và sau đó 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)
}
Và kiểm tra nhật ký của bạn.
Nhật ký của tôi:
// 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
Tóm tắt:
Nếu chúng tôi thiết lập setHasFixedSize(true)
và cập nhật dữ liệu của bộ điều hợp với thông báo cho người quan sát theo một cách khác ngoài cách gọi notifyDataSetChanged
, thì bạn có một số sai sót, bởi vì đó không phải là cuộc gọi đến onLayout
phương thức tái chế .