Saya kesulitan memahaminya setHasFixedSize()
. Saya tahu bahwa ini digunakan untuk pengoptimalan ketika ukuran RecyclerView
tidak berubah, dari dokumen.
Apa artinya itu? Dalam kasus yang paling umum, ListView
hampir selalu memiliki ukuran tetap. Dalam kasus apa itu bukan ukuran tetap? Apakah ini berarti real estat aktual yang ditempati di layar tumbuh bersama konten?
android
android-5.0-lollipop
android-recyclerview
SIr Codealot
sumber
sumber
Jawaban:
Sebuah sangat versi sederhana dari RecyclerView memiliki:
void onItemsInsertedOrRemoved() { if (hasFixedSize) layoutChildren(); else requestLayout(); }
Tautan ini menjelaskan mengapa biaya menelepon
requestLayout
mungkin mahal. Pada dasarnya setiap kali item disisipkan, dipindahkan atau dihapus, ukuran (lebar dan tinggi) RecyclerView mungkin berubah dan pada gilirannya ukuran tampilan lain dalam hierarki tampilan mungkin berubah. Ini sangat merepotkan jika item ditambahkan atau dihapus secara sering.Hindari tata letak yang tidak perlu lewat dengan menyetel
setHasFixedSize
ke true saat mengubah konten adaptor tidak mengubah tinggi atau lebarnya.Pembaruan: JavaDoc telah diperbarui untuk lebih menggambarkan apa yang sebenarnya dilakukan metode ini.
sumber
requestLayout
atau tidak setelah dataSet diperbarui.Dapat mengonfirmasi
setHasFixedSize
terkait dengan RecyclerView itu sendiri, dan bukan ukuran setiap item yang disesuaikan dengannya.Sekarang Anda dapat menggunakan
android:layout_height="wrap_content"
di RecyclerView, yang, antara lain, memungkinkan CollapsingToolbarLayout mengetahui bahwa ia tidak boleh diciutkan saat RecyclerView kosong. Ini hanya berfungsi saat Anda menggunakansetHasFixedSize(false)
di RecylcerView.Jika Anda menggunakan
setHasFixedSize(true)
RecyclerView, perilaku untuk mencegah CollapsingToolbarLayout agar tidak runtuh tidak akan berfungsi, meskipun RecyclerView memang kosong.Jika
setHasFixedSize
dikaitkan dengan ukuran item, seharusnya tidak berpengaruh apa pun saat RecyclerView tidak memiliki item.sumber
setHasFixedSize(true)
untuk membuatnya mengembang ketika item baru ditambahkan.hasFixedSize: set to true if adapter changes cannot affect the size of the RecyclerView.
Jadi meskipun ukuran item akan berubah, Anda masih dapat menyetelnya ke true.ListView memiliki fungsi bernama serupa yang menurut saya mencerminkan info tentang ukuran ketinggian item daftar individual. Dokumentasi untuk RecyclerView dengan cukup jelas menyatakan bahwa hal itu mengacu pada ukuran RecyclerView itu sendiri, bukan ukuran itemnya.
Dari komentar sumber RecyclerView di atas metode setHasFixedSize ():
* RecyclerView can perform several optimizations if it can know in advance that changes in * adapter content cannot change the size of the RecyclerView itself. * If your use of RecyclerView falls into this category, set this to true.
sumber
Jika kita memiliki
RecyclerView
denganmatch_parent
sebagai tinggi / lebar , kita harus menambahkansetHasFixedSize(true)
karena ukuranRecyclerView
itu sendiri tidak mengubah memasukkan atau menghapus item ke dalamnya.setHasFixedSize harus palsu jika kita memiliki RecyclerView dengan
wrap_content
sebagai tinggi / lebar karena setiap elemen dimasukkan oleh adaptor bisa mengubah ukuranRecycler
tergantung pada barang-barang dimasukkan / dihapus, sehingga, ukuranRecycler
akan berbeda setiap kali kita menambahkan / menghapus item.Agar lebih jelas, jika kita gunakan
<android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"/>
Kita bisa gunakan
my_recycler_view.setHasFixedSize(true)
<android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"/>
Kita harus menggunakan
my_recycler_view.setHasFixedSize(false)
, ini berlaku jika kita juga menggunakanwrap_content
lebarsumber
Wen kita set
setHasFixedSize(true)
padaRecyclerView
yang berarti ukuran pendaur ulang adalah tetap dan tidak terpengaruh oleh isi adaptor. Dan dalam halonLayout
ini tidak dipanggil pada pendaur ulang saat kita memperbarui data adaptor (tapi ada pengecualian).Mari kita lihat contoh:
RecyclerView
memilikiRecyclerViewDataObserver
( 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 ulangonLayout
, tetapi ada panggilan kerequestLayout
untuk memperbarui turunannya.Tetapi jika kita mengatur
setHasFixedSize(true)
dan memperbarui data adaptor melaluinotifyItemChanged
maka ada panggilan keonChange
default pendaur ulangRecyclerViewDataObserver
dan tidak ada panggilan ketriggerUpdateProcessor
. Dalam hal ini pendaur ulangonLayout
dipanggil setiap kali kita menyetelsetHasFixedSize
true
ataufalse
.// 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(); } }
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 menggunakanreplaceData
danreplaceOne
dengan pengaturansetHasFixedSize(true)
lalufalse
.// 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) }
Dan periksa log Anda.
Log saya:
// 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
Meringkaskan:
Jika kita menyetel
setHasFixedSize(true)
dan memperbarui data adaptor dengan memberi tahu pengamat dengan cara lain selain memanggilnotifyDataSetChanged
, maka Anda memiliki kinerja, karena tidak ada panggilan keonLayout
metode pendaur ulang .sumber
setHasFixedSize (true) berarti RecyclerView memiliki turunan (item) yang memiliki lebar dan tinggi tetap. Ini memungkinkan RecyclerView untuk mengoptimalkan lebih baik dengan mencari tahu tinggi dan lebar yang tepat dari seluruh daftar berdasarkan adaptor Anda.
sumber
Ini mempengaruhi animasi recyclerview, jika
false
.. animasi penyisipan dan penghapusan tidak akan ditampilkan. jadi pastikantrue
jika Anda menambahkan animasi untuk recyclerview.sumber
Jika ukuran RecyclerView (RecyclerView itu sendiri)
... tidak bergantung pada konten adaptor:
mRecyclerView.setHasFixedSize(true);
... tergantung pada konten adaptor:
mRecyclerView.setHasFixedSize(false);
sumber