Modul Status Tersimpan untuk ViewModel (Tampilan) Bagian dari Android Jetpack.
Konsep dan implementasi Jetpack Compose
Seperti yang telah disebutkan dalam Menyimpan Status UI, ViewModel objek dapat menangani
perubahan konfigurasi, sehingga Anda tidak perlu khawatir tentang status dalam rotasi
atau kasus lainnya. Namun, jika Anda perlu menangani penghentian proses yang diinisiasi sistem, Anda dapat menggunakan SavedStateHandle API sebagai cadangan.
Status UI biasanya disimpan atau dirujuk dalam ViewModel objek dan bukan
aktivitas, sehingga penggunaan onSaveInstanceState() memerlukan beberapa boilerplate yang dapat ditangani oleh
modul status tersimpan untuk Anda.
Saat menggunakan modul ini, objek ViewModel menerima objek SavedStateHandle
melalui konstruktornya. Objek ini adalah peta nilai kunci (key value) yang memungkinkan Anda menulis dan mengambil objek ke dan dari status tersimpan. Nilai-nilai ini akan dipertahankan setelah proses dihentikan oleh sistem dan akan tetap tersedia melalui objek yang sama.
Status tersimpan terikat dengan stack tugas Anda. Jika stack tugas Anda hilang, status tersimpan Anda juga akan hilang. Hal ini dapat terjadi saat Anda memaksa aplikasi berhenti, menghapus aplikasi dari menu terbaru, atau memulai ulang perangkat. Dalam kasus semacam ini, stack tugas akan hilang dan Anda tidak dapat memulihkan informasi dalam status tersimpan. Di skenario Penutupan status UI yang diinisialisasi pengguna, status tersimpan tidak dipulihkan. Di skenario yang diinisialisasi sistem, status tersimpan dipulihkan.
Penyiapan
Mulai dari Fragment 1.2.0 atau dependensi transitifnya
Activity 1.1.0, Anda dapat menerima SavedStateHandle sebagai argumen konstruktor
untuk ViewModel.
Kotlin
class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { ... }
Java
public class SavedStateViewModel extends ViewModel { private SavedStateHandle state; public SavedStateViewModel(SavedStateHandle savedStateHandle) { state = savedStateHandle; } ... }
Selanjutnya, Anda dapat mengambil instance ViewModel tanpa konfigurasi
tambahan apa pun. Factory ViewModel default menyediakan SavedStateHandle yang sesuai
untuk ViewModel Anda.
Kotlin
class MainFragment : Fragment() { val vm: SavedStateViewModel by viewModels() ... }
Java
class MainFragment extends Fragment { private SavedStateViewModel vm; public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { vm = new ViewModelProvider(this).get(SavedStateViewModel.class); ... } ... }
Saat memberikan instance ViewModelProvider.Factory kustom, Anda dapat
mengaktifkan penggunaan SavedStateHandle dengan memperluas
AbstractSavedStateViewModelFactory.
Menangani SavedStateHandle
Class SavedStateHandle adalah peta nilai kunci yang memungkinkan Anda menulis dan
mengambil data ke dan dari status tersimpan melalui metode set() dan
get().
Dengan menggunakan SavedStateHandle, nilai kueri akan dipertahankan di seluruh penghentian proses, sehingga memastikan pengguna melihat kumpulan data yang difilter yang sama sebelum dan setelah pembuatan ulang tanpa aktivitas atau fragmen perlu secara manual menyimpan, memulihkan, dan meneruskan nilai tersebut kembali ke ViewModel.
SavedStateHandle juga memiliki metode lain yang dapat Anda gunakan saat berinteraksi dengan peta nilai kunci:
contains(String key)- Memeriksa apakah ada nilai untuk kunci yang diberikan.remove(String key)- Menghapus nilai untuk kunci yang diberikan.keys()- Menampilkan semua kunci yang terdapat dalamSavedStateHandle.
Selain itu, Anda dapat mengambil nilai dari SavedStateHandle menggunakan holder data yang dapat diamati. Daftar jenis yang didukung adalah:
LiveData
Ambil nilai dari SavedStateHandle yang dienkapsulasi dalam LiveData
yang dapat diamati menggunakan getLiveData(). Saat nilai kunci diperbarui, LiveData akan menerima nilai baru. Biasanya, nilai ditetapkan karena interaksi pengguna, seperti memasukkan kueri untuk memfilter daftar data. Nilai yang diperbarui ini selanjutnya dapat digunakan untuk mengubah LiveData.
Kotlin
class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { val filteredData: LiveData<List<String>> = savedStateHandle.getLiveData<String>("query").switchMap { query -> repository.getFilteredData(query) } fun setQuery(query: String) { savedStateHandle["query"] = query } }
Java
public class SavedStateViewModel extends ViewModel { private SavedStateHandle savedStateHandle; public LiveData<List<String>> filteredData; public SavedStateViewModel(SavedStateHandle savedStateHandle) { this.savedStateHandle = savedStateHandle; LiveData<String> queryLiveData = savedStateHandle.getLiveData("query"); filteredData = Transformations.switchMap(queryLiveData, query -> { return repository.getFilteredData(query); }); } public void setQuery(String query) { savedStateHandle.set("query", query); } }
Jenis yang didukung
Data yang dipertahankan dalam SavedStateHandle disimpan dan dipulihkan sebagai Bundle,
beserta savedInstanceState lainnya untuk aktivitas atau
fragmen.
Menyimpan class yang tidak dapat dibagi-bagi
Jika class tidak mengimplementasi Parcelable atau Serializable dan tidak dapat dimodifikasi untuk mengimplementasikan salah satu antarmuka tersebut, maka Anda tidak dapat menyimpan instance class tersebut secara langsung ke dalam SavedStateHandle.
Mulai dari Lifecycle 2.3.0-alpha03, SavedStateHandle memungkinkan Anda menyimpan
objek apa pun dengan menyediakan logika sendiri untuk menyimpan dan memulihkan objek sebagai
Bundle menggunakan metode setSavedStateProvider().
SavedStateRegistry.SavedStateProvider adalah antarmuka yang menentukan
satu metode saveState() yang menampilkan Bundle berisi status
yang ingin Anda simpan. Saat SavedStateHandle siap menyimpan statusnya, saveState() akan dipanggil untuk mengambil Bundle dari SavedStateProvider dan menyimpan Bundle untuk kunci terkait.
Mari kita gunakan contoh sebuah aplikasi yang meminta gambar dari aplikasi kamera melalui
intent ACTION_IMAGE_CAPTURE, yang meneruskan file sementara tempat
kamera akan menyimpan gambar. TempFileViewModel merangkum logika untuk membuat file sementara tersebut.
Kotlin
class TempFileViewModel : ViewModel() { private var tempFile: File? = null fun createOrGetTempFile(): File { return tempFile ?: File.createTempFile("temp", null).also { tempFile = it } } }
Java
class TempFileViewModel extends ViewModel { private File tempFile = null; public TempFileViewModel() { } @NonNull public File createOrGetTempFile() { if (tempFile == null) { tempFile = File.createTempFile("temp", null); } return tempFile; } }
Untuk memastikan file sementara tidak hilang jika proses aktivitas dihentikan
dan kemudian dipulihkan, TempFileViewModel dapat menggunakan SavedStateHandle untuk
mempertahankan datanya. Untuk mengizinkan TempFileViewModel menyimpan datanya, implementasikan
SavedStateProvider dan tetapkan sebagai penyedia pada SavedStateHandle untuk ViewModel:
Kotlin
private fun File.saveTempFile() = bundleOf("path", absolutePath) class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { private var tempFile: File? = null init { savedStateHandle.setSavedStateProvider("temp_file") { // saveState() if (tempFile != null) { tempFile.saveTempFile() } else { Bundle() } } } fun createOrGetTempFile(): File { return tempFile ?: File.createTempFile("temp", null).also { tempFile = it } } }
Java
class TempFileViewModel extends ViewModel { private File tempFile = null; public TempFileViewModel(SavedStateHandle savedStateHandle) { savedStateHandle.setSavedStateProvider("temp_file", new TempFileSavedStateProvider()); } @NonNull public File createOrGetTempFile() { if (tempFile == null) { tempFile = File.createTempFile("temp", null); } return tempFile; } private class TempFileSavedStateProvider implements SavedStateRegistry.SavedStateProvider { @NonNull @Override public Bundle saveState() { Bundle bundle = new Bundle(); if (tempFile != null) { bundle.putString("path", tempFile.getAbsolutePath()); } return bundle; } } }
Untuk memulihkan data File saat pengguna kembali, ambil temp_file
Bundle dari SavedStateHandle. Ini adalah Bundle yang sama yang disediakan oleh
saveTempFile() berisi jalur absolut. Jalur absolut tersebut kemudian dapat
digunakan untuk membuat instance File baru.
Kotlin
private fun File.saveTempFile() = bundleOf("path", absolutePath) private fun Bundle.restoreTempFile() = if (containsKey("path")) { File(getString("path")) } else { null } class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { private var tempFile: File? = null init { val tempFileBundle = savedStateHandle.get<Bundle>("temp_file") if (tempFileBundle != null) { tempFile = tempFileBundle.restoreTempFile() } savedStateHandle.setSavedStateProvider("temp_file") { // saveState() if (tempFile != null) { tempFile.saveTempFile() } else { Bundle() } } } fun createOrGetTempFile(): File { return tempFile ?: File.createTempFile("temp", null).also { tempFile = it } } }
Java
class TempFileViewModel extends ViewModel { private File tempFile = null; public TempFileViewModel(SavedStateHandle savedStateHandle) { Bundle tempFileBundle = savedStateHandle.get("temp_file"); if (tempFileBundle != null) { tempFile = TempFileSavedStateProvider.restoreTempFile(tempFileBundle); } savedStateHandle.setSavedStateProvider("temp_file", new TempFileSavedStateProvider()); } @NonNull public File createOrGetTempFile() { if (tempFile == null) { tempFile = File.createTempFile("temp", null); } return tempFile; } private class TempFileSavedStateProvider implements SavedStateRegistry.SavedStateProvider { @NonNull @Override public Bundle saveState() { Bundle bundle = new Bundle(); if (tempFile != null) { bundle.putString("path", tempFile.getAbsolutePath()); } return bundle; } @Nullable private static File restoreTempFile(Bundle bundle) { if (bundle.containsKey("path") { return File(bundle.getString("path")); } return null; } } }
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Menyimpan status UI
- Bekerja dengan objek data yang dapat diamati
- Membuat ViewModel dengan dependensi