Anda melakukan ini dengan menerapkan View#onSaveInstanceState
dan View#onRestoreInstanceState
dan memperluas View.BaseSavedState
kelas.
public class CustomView extends View {
private int stateToSave;
...
@Override
public Parcelable onSaveInstanceState() {
//begin boilerplate code that allows parent classes to save state
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
//end
ss.stateToSave = this.stateToSave;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
//begin boilerplate code so parent classes can restore state
if(!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
//end
this.stateToSave = ss.stateToSave;
}
static class SavedState extends BaseSavedState {
int stateToSave;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
this.stateToSave = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(this.stateToSave);
}
//required field that makes Parcelables from a Parcel
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
Pekerjaan dibagi antara kelas View dan SavedState. Anda harus melakukan semua pekerjaan membaca dan menulis ke dan dari Parcel
dalam SavedState
kelas. Kemudian kelas View Anda dapat melakukan pekerjaan mengekstraksi anggota negara dan melakukan pekerjaan yang diperlukan untuk mengembalikan kelas ke status yang valid.
Catatan: View#onSavedInstanceState
dan View#onRestoreInstanceState
dipanggil secara otomatis untuk Anda jika View#getId
mengembalikan nilai> = 0. Ini terjadi ketika Anda memberikannya id dalam xml atau menelepon setId
secara manual. Kalau tidak, Anda harus menelepon View#onSaveInstanceState
dan menulis Parcelable dikembalikan ke paket Anda masuk Activity#onSaveInstanceState
untuk menyelamatkan negara dan kemudian membacanya dan meneruskannya View#onRestoreInstanceState
dari Activity#onRestoreInstanceState
.
Contoh sederhana lain dari ini adalah CompoundButton
onSaveInstanceState()
danonRestoreInstanceState()
harusprotected
(seperti superclass mereka), bukanpublic
. Tidak ada alasan untuk mengekspos mereka ...BaseSaveState
untuk kelas yang memperluas RecyclerView, Anda mendapatkanParcel﹕ Class not found when unmarshalling: android.support.v7.widget.RecyclerView$SavedState java.lang.ClassNotFoundException: android.support.v7.widget.RecyclerView$SavedState
sehingga Anda perlu melakukan perbaikan bug yang ditulis di sini: github.com/ksoichiro/Android-ObservableScrollView/commit/… (menggunakan ClassLoader dari RecyclerView.class untuk memuat super state)Saya pikir ini adalah versi yang jauh lebih sederhana.
Bundle
adalah tipe bawaan yang menerapkanParcelable
sumber
onRestoreInstanceState
dipanggil dengan Bundle jikaonSaveInstanceState
mengembalikan Bundle?OnRestoreInstance
diwariskan. Kami tidak dapat mengubah header.Parcelable
hanyalah sebuah antarmuka,Bundle
merupakan implementasi untuk itu.View
status dasar bukan aBundle
. Tentu saja, itu benar saat ini, tetapi Anda mengandalkan fakta implementasi saat ini yang tidak dijamin benar.Berikut adalah varian lain yang menggunakan campuran dari dua metode di atas. Menggabungkan kecepatan dan ketepatan
Parcelable
dengan kesederhanaanBundle
:sumber
State
dari paket. Silakan lihat di: charlesharley.com/2012/programming/…Jawaban di sini sudah bagus, tetapi tidak selalu berfungsi untuk Grup View kustom. Untuk mendapatkan semua Tampilan kustom untuk mempertahankan statusnya, Anda harus mengganti
onSaveInstanceState()
danonRestoreInstanceState(Parcelable state)
di setiap kelas. Anda juga perlu memastikan mereka semua memiliki id unik, apakah mereka digelembungkan dari xml atau ditambahkan secara programatis.Apa yang saya hasilkan sangat mirip dengan jawaban Kobor42, tetapi kesalahannya tetap karena saya menambahkan Tampilan ke ViewGroup kustom secara terprogram dan tidak menetapkan id unik.
Tautan yang dibagikan oleh mato akan berfungsi, tetapi itu berarti tidak ada satu pun Tampilan individu yang mengelola keadaan mereka sendiri - seluruh negara disimpan dalam metode ViewGroup.
Masalahnya adalah bahwa ketika beberapa ViewGroup ini ditambahkan ke tata letak, id elemen mereka dari xml tidak lagi unik (jika didefinisikan dalam xml). Saat runtime, Anda dapat memanggil metode statis
View.generateViewId()
untuk mendapatkan id unik untuk Tampilan. Ini hanya tersedia dari API 17.Ini kode saya dari ViewGroup (abstrak, dan mOriginalValue adalah variabel tipe):
sumber
Saya punya masalah yang onRestoreInstanceState memulihkan semua tampilan kustom saya dengan keadaan tampilan terakhir. Saya menyelesaikannya dengan menambahkan dua metode ini ke tampilan kustom saya:
sumber
Alih-alih menggunakan
onSaveInstanceState
danonRestoreInstanceState
, Anda juga dapat menggunakan aViewModel
. Buat model data Anda diperluasViewModel
, dan kemudian Anda bisa menggunakanViewModelProviders
untuk mendapatkan contoh yang sama dari model Anda setiap kali Kegiatan diciptakan kembali:Untuk menggunakan
ViewModelProviders
, tambahkan yang berikut kedependencies
dalamapp/build.gradle
:Perhatikan bahwa Anda
MyActivity
meluasFragmentActivity
bukan hanya memperpanjangActivity
.Anda dapat membaca lebih lanjut tentang ViewModels di sini:
sumber
ViewModel
sangat berguna jika Anda memiliki set data besar untuk dipertahankan selama perubahan status, seperti rotasi layar. Saya lebih suka menggunakanViewModel
daripada menulis ke dalamApplication
karena jelas cakupannya, dan saya dapat memiliki beberapa Kegiatan dari Aplikasi yang sama berperilaku dengan benar.Saya menemukan bahwa jawaban ini menyebabkan beberapa crash pada Android versi 9 dan 10. Saya pikir ini pendekatan yang bagus tetapi ketika saya melihat beberapa kode Android saya menemukan itu hilang konstruktor. Jawabannya cukup lama sehingga pada saat itu mungkin tidak perlu. Ketika saya menambahkan konstruktor yang hilang dan memanggilnya dari pencipta, crash diperbaiki.
Jadi di sini adalah kode yang diedit:
sumber
Untuk menambah jawaban lain - jika Anda memiliki beberapa tampilan majemuk khusus dengan ID yang sama dan semuanya dipulihkan dengan keadaan tampilan terakhir pada perubahan konfigurasi, yang perlu Anda lakukan adalah memberi tahu pandangan untuk hanya mengirim save / restore events untuk dirinya sendiri dengan menimpa beberapa metode.
Untuk penjelasan tentang apa yang terjadi dan mengapa ini berhasil, lihat posting blog ini . Pada dasarnya ID tampilan anak-anak pandangan majemuk Anda dibagikan oleh setiap tampilan majemuk dan pemulihan keadaan menjadi membingungkan. Dengan hanya mengirim status untuk tampilan halaman majemuk itu sendiri, kami mencegah anak-anak mereka dari menerima pesan campuran dari tampilan halaman lain.
sumber