Saya punya pertanyaan tentang RecyclerView.State Android .
Saya menggunakan RecyclerView, bagaimana saya bisa menggunakan dan mengikatnya dengan RecyclerView.State?
Tujuan saya adalah untuk menyimpan posisi gulir RecyclerView .
Saya punya pertanyaan tentang RecyclerView.State Android .
Saya menggunakan RecyclerView, bagaimana saya bisa menggunakan dan mengikatnya dengan RecyclerView.State?
Tujuan saya adalah untuk menyimpan posisi gulir RecyclerView .
Bagaimana rencana Anda untuk menyimpan posisi terakhir yang disimpan RecyclerView.State
?
Anda selalu bisa mengandalkan keadaan penyelamatan yang baik. Perluas RecyclerView
dan timpa onSaveInstanceState () dan onRestoreInstanceState()
:
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null && layoutManager instanceof LinearLayoutManager){
mScrollPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
}
SavedState newState = new SavedState(superState);
newState.mScrollPosition = mScrollPosition;
return newState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
if(state != null && state instanceof SavedState){
mScrollPosition = ((SavedState) state).mScrollPosition;
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null){
int count = layoutManager.getItemCount();
if(mScrollPosition != RecyclerView.NO_POSITION && mScrollPosition < count){
layoutManager.scrollToPosition(mScrollPosition);
}
}
}
}
static class SavedState extends android.view.View.BaseSavedState {
public int mScrollPosition;
SavedState(Parcel in) {
super(in);
mScrollPosition = in.readInt();
}
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mScrollPosition);
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
Memperbarui
Mulai dari
recyclerview:1.2.0-alpha02
rilisStateRestorationPolicy
telah diperkenalkan. Ini bisa menjadi pendekatan yang lebih baik untuk masalah yang diberikan.Topik ini telah dibahas pada artikel medium pengembang android .
Juga, @ rubén-viguera membagikan lebih banyak detail dalam jawaban di bawah ini. https://stackoverflow.com/a/61609823/892500
Jawaban lama
Jika Anda menggunakan LinearLayoutManager, LinearLayoutManager dilengkapi dengan save api linearLayoutManagerInstance.onSaveInstanceState () dan pulihkan api linearLayoutManagerInstance.onRestoreInstanceState (...)
Dengan itu, Anda dapat menyimpan parsel yang dikembalikan ke negara bagian Anda. misalnya,
, dan pulihkan posisi pemulihan dengan keadaan yang Anda simpan. misalnya,
Untuk menyelesaikan semuanya, kode akhir Anda akan terlihat seperti ini
Edit: Anda juga dapat menggunakan apis yang sama dengan GridLayoutManager, karena ini adalah subclass dari LinearLayoutManager. Terima kasih @wegsehen atas sarannya.
Edit: Ingat, jika Anda juga memuat data di thread latar belakang, Anda perlu memanggil onRestoreInstanceState dalam metode onPostExecute / onLoadFinished Anda agar posisi dipulihkan setelah orientasi berubah, mis.
sumber
RecyclerView
tetapi tidak jika Anda memilikiViewPager
dengan aRecycerView
di setiap halaman.onCreateView
, tetapi setelah memuat data. Lihat jawaban @Farmaker di sini.Toko
Mengembalikan
dan jika itu tidak berhasil, coba
Simpan
onPause()
dan pulihkanonResume()
sumber
lastFirstVisiblePosition
ke0
setelah memulihkannya. Kasus ini berguna jika Anda memiliki fragmen / aktivitas yang memuat data berbeda dalam satuRecyclerView
, misalnya, aplikasi file explorer.SwipeRefreshLayout
?RecyclerView
Saya ingin menyimpan posisi gulir Recycler View saat menavigasi keluar dari aktivitas daftar saya, lalu mengklik tombol kembali untuk menavigasi kembali. Banyak solusi yang disediakan untuk masalah ini jauh lebih rumit daripada yang dibutuhkan atau tidak berfungsi untuk konfigurasi saya, jadi saya pikir saya akan membagikan solusi saya.
Pertama-tama simpan status instance Anda di onPause seperti yang telah ditunjukkan banyak orang. Saya pikir perlu ditekankan di sini bahwa versi onSaveInstanceState ini adalah metode dari kelas RecyclerView.LayoutManager.
Kunci agar ini berfungsi dengan benar adalah memastikan Anda memanggil onRestoreInstanceState setelah Anda memasang adaptor, seperti yang ditunjukkan beberapa di utas lain. Namun panggilan metode sebenarnya jauh lebih sederhana daripada yang telah ditunjukkan banyak orang.
sumber
Saya mengatur variabel di onCreate (), menyimpan posisi gulir di onPause () dan mengatur posisi gulir di onResume ()
sumber
Anda tidak perlu lagi menyimpan dan memulihkan keadaan sendiri. Jika Anda menyetel ID unik di xml dan recyclerView.setSaveEnabled (true) (true secara default), sistem akan otomatis melakukannya. Berikut lebih lanjut tentang ini: http://trickyandroid.com/saving-android-view-state-correctly/
sumber
Semua manajer tata letak yang dibundel di pustaka dukungan sudah tahu cara menyimpan dan memulihkan posisi gulir.
Posisi gulir dipulihkan pada tata letak pertama yang terjadi ketika kondisi berikut terpenuhi:
RecyclerView
RecyclerView
Biasanya Anda menyetel pengelola tata letak dalam XML sehingga yang harus Anda lakukan sekarang adalah
RecyclerView
Anda dapat melakukan ini kapan saja, tidak dibatasi
Fragment.onCreateView
atauActivity.onCreate
.Contoh: Pastikan adaptor terpasang setiap kali data diperbarui.
Posisi gulir yang disimpan dihitung dari data berikut:
Oleh karena itu, Anda dapat mengharapkan sedikit ketidakcocokan, misalnya jika item Anda memiliki dimensi berbeda dalam orientasi potret dan lanskap.
The
RecyclerView
/ScrollView
/ apapun perlu memilikiandroid:id
bagi negara untuk diselamatkan.sumber
LinearLayoutManager.SavedState
: cs.android.com/androidx/platform/frameworks/support/+/…Berikut adalah Pendekatan saya untuk menyimpannya dan mempertahankan status recyclerview dalam sebuah fragmen. Pertama, tambahkan perubahan konfigurasi pada aktivitas induk Anda seperti kode di bawah ini.
Kemudian di Fragmen Anda, deklarasikan metode instance ini
Tambahkan kode di bawah ini dalam metode @onPause Anda
Tambahkan Metode onConfigartionChanged seperti di bawah ini.
Pendekatan ini akan menyelesaikan masalah Anda. jika Anda memiliki pengelola tata letak yang berbeda, maka ganti saja pengelola tata letak atas.
sumber
Ini adalah cara saya mengembalikan posisi RecyclerView dengan GridLayoutManager setelah rotasi ketika Anda perlu memuat ulang data dari internet dengan AsyncTaskLoader.
Buat variabel global Parcelable dan GridLayoutManager dan string final statis:
Simpan status gridLayoutManager di onSaveInstance ()
Pulihkan di onRestoreInstanceState
Kemudian saat loader mengambil data dari internet, Anda mengembalikan posisi recyclerview di onLoadFinished ()
..tentu saja Anda harus membuat instance gridLayoutManager di dalam onCreate. Bersulang
sumber
Saya memiliki persyaratan yang sama, tetapi solusi di sini tidak cukup membantu saya, karena sumber data untuk recyclerView.
Saya mengekstrak status LinearLayoutManager RecyclerViews di onPause ()
Parcelable
state
disimpan dionSaveInstanceState(Bundle outState)
, dan diekstraksi lagi dionCreate(Bundle savedInstanceState)
, saatsavedInstanceState != null
.Namun, adaptor recyclerView diisi dan diperbarui oleh objek ViewModel LiveData yang ditampilkan oleh panggilan DAO ke database Room.
Saya akhirnya menemukan bahwa memulihkan status instance langsung setelah data disetel di adaptor akan menjaga status gulir di seluruh rotasi.
Saya menduga ini baik karena
LinearLayoutManager
status yang saya pulihkan telah ditimpa ketika data dikembalikan oleh panggilan database, atau status yang dipulihkan tidak berarti terhadap LinearLayoutManager 'kosong'.Jika data adaptor tersedia secara langsung (misalnya, tidak terkait pada panggilan database), maka memulihkan status instance di LinearLayoutManager bisa dilakukan setelah adaptor disetel pada recyclerView.
Perbedaan antara kedua skenario tersebut membuat saya bertahan lama.
sumber
Di Android API Level 28, saya cukup memastikan bahwa saya menyiapkan
LinearLayoutManager
danRecyclerView.Adapter
dalamFragment#onCreateView
metode saya , dan semuanya Just Worked ™ ️. Saya tidak perlu melakukan apa punonSaveInstanceState
atauonRestoreInstanceState
bekerja.Jawaban Eugen Pechanec menjelaskan mengapa ini berhasil.
sumber
Mulai dari versi 1.2.0-alpha02 library androidx recyclerView, sekarang dikelola secara otomatis. Tambahkan saja dengan:
Dan gunakan:
Enum StateRestorationPolicy memiliki 3 opsi:
Perhatikan bahwa pada saat jawaban ini, pustaka recyclerView masih dalam alpha03, tetapi fase alfa tidak cocok untuk tujuan produksi .
sumber
Bagi saya, masalahnya adalah saya menyiapkan layoutmanager baru setiap kali saya mengganti adaptor saya, kehilangan posisi gulir antrean di recyclerView.
sumber
Saya hanya ingin berbagi masalah yang baru-baru ini saya hadapi dengan RecyclerView. Saya berharap siapa pun yang mengalami masalah yang sama akan mendapat manfaat.
Persyaratan Proyek Saya: Jadi saya memiliki RecyclerView yang mencantumkan beberapa item yang dapat diklik di Aktivitas Utama saya (Aktivitas-A). Saat Item diklik, Aktivitas baru ditampilkan dengan Detail Item (Aktivitas-B).
Saya mengimplementasikan dalam file Manifest bahwa Activity-A adalah induk dari Activity-B, dengan begitu, saya memiliki tombol kembali atau home pada ActionBar dari Activity-B
Masalah: Setiap kali saya menekan tombol Back atau Home di Activity-B ActionBar, Activity-A masuk ke Activity Life Cycle penuh mulai dari onCreate ()
Meskipun saya mengimplementasikan onSaveInstanceState () yang menyimpan Daftar Adaptor RecyclerView, ketika Activity-A memulai siklus hidupnya, saveInstanceState selalu nol dalam metode onCreate ().
Menggali lebih lanjut di internet, saya menemukan masalah yang sama tetapi orang tersebut memperhatikan bahwa tombol Kembali atau Beranda di bawah perangkat Anroid (tombol Kembali / Beranda Default), Aktivitas-A tidak masuk ke Siklus Hidup Aktivitas.
Larutan:
Saya mengaktifkan tombol beranda atau kembali pada Aktivitas-B
Di bawah metode onCreate () tambahkan baris ini supportActionBar? .SetDisplayHomeAsUpEnabled (true)
Dalam metode onOptionsItemSelected () overide fun, saya memeriksa item.ItemId di mana item diklik berdasarkan id. Id untuk tombol kembali adalah
android.R.id.home
Kemudian implementasikan panggilan fungsi finish () di dalam android.R.id.home
Ini akan mengakhiri Aktivitas-B dan membawa Aktivitas-A tanpa melalui seluruh siklus hidup.
Untuk kebutuhan saya, sejauh ini ini adalah solusi terbaik.
sumber
Saya memiliki masalah yang sama dengan perbedaan kecil, saya menggunakan Databinding , dan saya menyetel adaptor recyclerView dan layoutManager dalam metode binding.
Masalahnya adalah pengikatan data terjadi setelah onResume jadi itu menyetel ulang layoutManager saya setelah onResume dan itu berarti itu menggulir kembali ke tempat semula setiap waktu. Jadi, ketika saya berhenti menyetel layoutManager dalam metode adaptor Databinding, itu berfungsi dengan baik lagi.
sumber
Dalam kasus saya, saya menyetel RecyclerView
layoutManager
dalam XML dan dalamonViewCreated
. Menghapus tugas dionViewCreated
memperbaikinya.sumber
Activity.java:
Why I'm using
OnSaveInstanceState()
inonPause()
means, While beralih ke aktivitas lain onPause akan dipanggil. Ini akan menyimpan posisi gulir itu dan memulihkan posisi saat kita kembali dari aktivitas lain.sumber