Menyimpan Status UI

Mempertahankan dan memulihkan status UI aktivitas secara tepat waktu pada aktivitas yang diprakarsai oleh sistem atau penghancuran aplikasi adalah bagian penting dari pengalaman pengguna. Dalam kasus ini pengguna mengharapkan status UI tetap sama, tetapi sistem menghancurkan aktivitas dan status apa pun yang tersimpan di dalamnya.

Untuk menjembatani kesenjangan antara harapan pengguna dan perilaku sistem, gunakan kombinasi objek ViewModel , metode onSaveInstanceState(), dan/atau penyimpanan lokal untuk mempertahankan status UI pada transisi aplikasi dan instance aktivitas tersebut. Menentukan cara menggabungkan opsi-opsi ini bergantung pada kompleksitas data UI Anda, kasus penggunaan untuk aplikasi Anda, dan pertimbangan kecepatan pengambilan versus penggunaan memori.

Terlepas dari pendekatan yang diambil, Anda harus memastikan bahwa aplikasi memenuhi harapan pengguna sehubungan dengan status UI mereka, dan memberikan UI yang mulus dan cepat (menghindari keterlambatan waktu dalam memuat data ke dalam UI, terutama setelah perubahan konfigurasi yang sering terjadi, seperti rotasi). Biasanya, Anda harus menggunakan ViewModel dan onSaveInstanceState().

Halaman ini membahas harapan pengguna tentang status UI, opsi yang tersedia untuk mempertahankan status, keseimbangan, dan keterbatasan masing-masing.

Harapan pengguna dan perilaku sistem

Bergantung pada tindakan yang dilakukan oleh pengguna, mereka mengharapkan status aktivitas dihapus atau status dipertahankan. Pada beberapa kasus, sistem secara otomatis melakukan tindakan yang diharapkan oleh pengguna. Dalam kasus lain, sistem melakukan kebalikan dari tindakan yang diharapkan oleh pengguna.

Penutupan status UI yang diprakarsai oleh pengguna

Pengguna mengharapkan bahwa saat mereka memulai aktivitas, status UI sementara dari aktivitas tersebut akan tetap sama hingga pengguna sepenuhnya menutup aktivitas. Pengguna dapat sepenuhnya menutup aktivitas dengan:

  • menekan tombol kembali
  • menggeser aktivitas di luar layar Ringkasan (Terbaru)
  • menuju ke atas dari aktivitas
  • menutup aplikasi dari layar Setelan
  • menyelesaikan semacam aktivitas "penyelesaian" (yang didukung oleh Activity.finish())

Asumsi pengguna dalam kasus penutupan yang menyeluruh ini adalah bahwa pengguna secara permanen menutup aktivitas, dan jika aktivitas dibuka kembali, pengguna berharap aktivitas dimulai dari status bersih. Perilaku sistem yang mendasari skenario penutupan ini sesuai dengan harapan pengguna - instance aktivitas akan dihancurkan dan dihapus dari memori, beserta status apa saja yang tersimpan di dalamnya dan catatan status instance tersimpan apa saja yang terkait dengan aktivitas.

Ada beberapa pengecualian aturan ini terkait penutupan menyeluruh -- misalnya pengguna mungkin berharap browser membawa pengguna ke halaman web yang dilihat sebelum keluar dari browser menggunakan tombol kembali.

Penutupan status UI yang diprakarsai oleh sistem

Pengguna berharap status UI aktivitas tetap sama selama perubahan konfigurasi, seperti rotasi atau beralih ke mode banyak jendela. Akan tetapi, secara default sistem menghancurkan aktivitas saat perubahan konfigurasi tersebut terjadi, dengan menghapus status UI apa saja yang tersimpan di instance aktivitas. Untuk mempelajari lebih lanjut konfigurasi perangkat, lihat halaman Referensi konfigurasi. Perlu diperhatikan, Anda dapat (meski tidak direkomendasikan) mengganti perilaku default untuk perubahan konfigurasi. Lihat Menangani Sendiri Perubahan Konfigurasi untuk detail selengkapnya.

Pengguna juga berharap status UI aktivitas tetap sama jika pengguna untuk sementara beralih ke aplikasi lain, lalu kembali ke aplikasi Anda nanti. Misalnya, pengguna melakukan penelusuran di aktivitas penelusuran, lalu menekan tombol layar utama atau menjawab panggilan telepon - saat pengguna kembali ke aktivitas penelusuran, pengguna berharap menemukan kata kunci penelusuran dan hasilnya tetap ada di sana, persis seperti sebelumnya.

Dalam skenario ini, aplikasi ditempatkan di latar belakang, sistem melakukan yang terbaik untuk mempertahankan proses aplikasi dalam memori. Akan tetapi, sistem dapat menghancurkan proses aplikasi saat pengguna berinteraksi dengan aplikasi lain. Dalam kasus tersebut, instance aktivitas dihancurkan, beserta status apa saja yang tersimpan di dalamnya. Saat pengguna meluncurkan ulang aplikasi, aktivitas secara tidak terduga berada dalam status bersih. Untuk mempelajari lebih lanjut kematian proses, lihat Proses dan Siklus Hidup Aplikasi.

Opsi untuk mempertahankan status UI

Jika harapan pengguna tentang status UI tidak sesuai dengan perilaku sistem default, Anda harus menyimpan dan memulihkan status UI pengguna untuk memastikan bahwa penghancuran yang diprakarsai oleh sistem transparan kepada pengguna.

Tiap opsi untuk mempertahankan status UI bervariasi di sepanjang dimensi berikut yang memengaruhi pengalaman pengguna:

ViewModel Status instance tersimpan Penyimpanan persisten
Lokasi penyimpanan dalam memori diserialisasi ke disk pada disk atau jaringan
Tetap bertahan saat terjadi perubahan konfigurasi Ya Ya Ya
Tetap bertahan saat terjadi kematian proses yang diprakarsai oleh sistem Tidak Ya Ya
Tetap bertahan saat terjadi penutupan aktivitas menyeluruh pengguna/onFinish() Tidak Tidak Ya
Keterbatasan data objek kompleks tidak masalah, tetapi ruang dibatasi oleh memori yang tersedia hanya untuk jenis primitif dan objek kecil sederhana seperti String hanya dibatasi oleh ruang disk atau biaya/waktu pengambilan dari resource jaringan
Waktu baca/tulis cepat (hanya akses memori) lambat (memerlukan serialisasi/deserialisasi dan akses disk) lambat (memerlukan akses disk atau transaksi jaringan)

Menggunakan ViewModel untuk menangani perubahan konfigurasi

ViewModel ideal untuk menyimpan dan mengelola data terkait UI saat pengguna aktif menggunakan aplikasi. Ini memungkinkan akses cepat ke data UI dan membantu Anda menghindari pengambilan kembali data dari jaringan atau disk selama rotasi, perubahan ukuran jendela, dan perubahan konfigurasi lainnya yang umum terjadi. Untuk mempelajari cara mengimplementasikan ViewModel, lihat panduan ViewModel.

ViewModel menyimpan data dalam memori, yang artinya lebih murah diambil daripada data dari disk atau jaringan. ViewModel terkait dengan aktivitas (atau beberapa pemilik siklus hidup lainnya) - dan tetap berada dalam memori selama perubahan konfigurasi dan sistem secara otomatis mengaitkan ViewModel dengan instance aktivitas baru yang dihasilkan dari perubahan konfigurasi.

ViewModel otomatis dihancurkan oleh sistem saat pengguna keluar dari aktivitas Anda atau fragmen atau jika Anda memanggil finish(), yang artinya status akan dihapus seperti yang diharapkan oleh pengguna dalam skenario ini.

Tidak seperti status instance yang tersimpan, ViewModel dihancurkan selama kematian proses yang diprakarsai oleh sistem. Itu sebabnya Anda harus menggunakan objek ViewModel yang dikombinasikan dengan onSaveInstanceState() (atau persistensi disk lainnya), menyembunyikan ID dalam savedInstanceState untuk membantu melihat model memuat ulang data setelah kematian sistem.

Jika Anda telah menyiapkan solusi dalam memori untuk menyimpan status UI selama perubahan konfigrasi, Anda mungkin tidak perlu menggunakan ViewModel.

Menggunakan onSaveInstanceState() sebagai cadangan untuk menangani kematian proses yang diprakarsai oleh sistem

Callback onSaveInstanceState() menyimpan data yang diperlukan untuk memuat ulang status pengontrol UI, seperti aktivitas atau fragmen, jika sistem menghancurkan dan kemudian membuat ulang pengontrol tersebut. Untuk mempelajari cara mengimplementasikan status instance yang tersimpan, lihat Menyimpan dan memulihkan status aktivitas di panduan Siklus Hidup Aktivitas.

Paket status instance yang tersimpan tetap bertahan saat terjadi perubahan konfigurasi dan kematian proses, tetapi dibatasi oleh jumlah penyimpanan dan kecepatan karena onSavedInstanceState() melakukan serialisasi data ke disk. Serialisasi dapat menghabiskan banyak memori jika objek yang diserialisasi rumit. Karena proses ini terjadi pada thread utama selama perubahan konfigurasi, serialisasi dapat menyebabkan penurunan frame dan tersendatnya visual jika memerlukan waktu terlalu lama.

Jangan gunakan simpan onSavedInstanceState() untuk menyimpan data dalam jumlah besar, seperti bitmap, atau struktur data kompleks yang memerlukan serialisasi atau deserialisasi yang panjang. Simpan hanya jenis primitif dan objek yang kecil dan sederhana seperti String. Oleh karena itu, gunakan onSaveInstanceState() untuk menyimpan data dalam jumlah minimal yang diperlukan, seperti ID, untuk membuat ulang data yang diperlukan guna memulihkan UI kembali ke status sebelumnya jika mekanisme persistensi lain gagal. Sebagian besar aplikasi harus mengimplementasikan onSaveInstanceState() untuk menangani kematian proses yang diprakarsai oleh sistem.

Bergantung pada kasus penggunan aplikasi, Anda mungkin tidak perlu menggunakan onSaveInstanceState() sama sekali. Misalnya, browser mungkin membawa pengguna kembali ke halaman web yang mereka lihat sebelum keluar dari browser. Jika aktivitas Anda menunjukkan perilaku seperti ini, Anda dapat membatalkannya menggunakan onSaveInstanceState() dan mempertahankan semuanya secara lokal.

Selain itu, saat Anda membuka aktivitas dari suatu intent, paket yang berisikan tambahan dikirimkan ke aktivitas saat konfigurasi berubah dan saat sistem memulihkan aktivitas. Jika sepotong data status UI, seperti kueri penelusuran, diteruskan sebagai tambahan intent saat aktivitas diluncurkan, Anda dapat menggunakan paket tambahan, bukan paket onSaveInstanceState(). Untuk mempelajari lebih lanjut tambahan intent, lihat Intent dan Filter Intent.

Dalam salah satu skenario ini, Anda tetap harus menggunakan ViewModel untuk menghindari pemborosan siklus pemuatan ulang data dari database selama perubahan konfigurasi.

Jika ingin mempertahankan data UI yang sederhana dan ringan, Anda cukup menggunakan onSaveInstanceState() untuk mempertahankan data status.

Catatan: Anda sekarang dapat memberikan akses ke status tersimpan dalam objek ViewModel dengan modul Status Tersimpan untuk ViewModel (saat ini dalam Alfa). Status tersimpan ini dapat diakses melalui objek yang disebut SavedStateHandle. Anda dapat melihat cara penggunaannya dalam codelab komponen berbasis siklus hidup Android.

Menggunakan persistensi lokal untuk menangani kematian proses untuk data yang kompleks atau besar

Penyimpanan lokal persisten, seperti database atau preferensi bersama, akan bertahan selama aplikasi Anda diinstal di perangkat pengguna (kecuali pengguna menghapus data untuk aplikasi). Meski penyimpanan lokal tersebut bertahan selama aktivitas yang diprakarsai oleh sistem dan kematian proses aplikasi, penyimpanan lokal tersebut dapat menjadi mahal untuk diambil karena harus dibaca dari penyimpanan lokal ke dalam memori. Biasanya penyimpanan lokal persisten mungkin sudah menjadi bagian dari arsitektur aplikasi untuk menyimpan semua data yang ingin Anda pertahankan jika Anda membuka dan menutup aplikasi.

ViewModel status instance tersimpan bukan solusi penyimpanan jangka panjang dan oleh karena itu bukan pengganti penyimpanan lokal, seperti database. Anda harus menggunakan mekanisme ini hanya untuk menyimpan status UI sementara dan menggunakan penyimpanan persisten untuk data aplikasi lainnya. Lihat Panduan Arsitektur Aplikasi untuk detail selengkapnya tentang cara memanfaatkan penyimpanan lokal untuk mempertahankan data model aplikasi dalam jangka panjang (mis., setelah perangkat dinyalakan ulang berkali-kali).

Mengelola status UI: membagi dan menyelesaikan tugas

Anda dapat menyimpan dan memulihkan status UI secara efisien dengan cara membagi tugas ke beberapa jenis mekanimse persistensi. Biasanya, masing-masing mekanisme ini harus menyimpan jenis data yang berbeda yang digunakan dalam aktivitas, berdasarkan keseimbangan kompleksitas data, kecepatan akses, dan masa pakai:

  • Persistensi lokal: Menyimpan semua data yang ingin Anda pertahankan saat membuka dan menutup aktivitas.
    • Contoh: Kumpulan objek lagu, yang dapat mencakup file audio dan metadata.
  • ViewModel: Menyimpan semua data yang diperlukan untuk menampilkan Pengontrol UI yang terkait ke dalam memori.
    • Contoh: Objek lagu dari penelusuran terbaru dan kueri penelusuran terbaru.
  • onSaveInstanceState(): Menyimpan sejumlah kecil data yang diperlukan untuk memuat ulang status aktivitas dengan mudah jika sistem terhenti dan kemudian membuat ulang pengontrol UI. Daripada menyimpan objek kompleks di sini, pertahankan objek kompleks pada penyimpanan lokal dan simpan ID unik objek tersebut di onSaveInstanceState().
    • Contoh: Menyimpan kueri penelusuran terbaru.

Sebagai contoh, pertimbangkan aktivitas yang memungkinkan Anda menelusuri koleksi lagu Anda. Berikut ini adalah cara penanganan berbagai peristiwa yang berbeda:

Saat pengguna menambahkan sebuah lagu, ViewModel segera mendelegasikan untuk mempertahankan data ini secara lokal. Jika lagu yang baru ditambahkan ini harus ditampilkan pada UI, Anda juga harus memperbarui data dalam objek ViewModel untuk mencerminkan penambahan lagu tersebut. Ingatlah untuk melakukan semua penyisipan database dari thread utama.

Saat pengguna menelusuri sebuah lagu, data lagu kompleks apa pun yang Anda muat dari database untuk Pengontrol UI harus segera disimpan dalam objek ViewModel . Anda juga harus menyimpan kueri penelusuran tersebut dalam objek ViewModel.

Saat aktivitas ini beralih ke latar belakang, sistem akan memanggil onSaveInstanceState(). Anda harus menyimpan kueri penelusuran dalam paket onSaveInstanceState(). Jumlah data yang kecil seperti ini mudah untuk disimpan. Data ini juga merupakan semua informasi yang Anda perlukan untuk memulihkan aktivitas kembali ke statusnya saat ini.

Memulihkan status kompleks: menyusun ulang setiap bagian

Jika saatnya bagi pengguna untuk kembali ke aktivitas, ada dua kemungkinan skenario dalam membuat ulang aktivitas:

  • Aktivitas dibuat ulang setelah dihentikan oleh sistem. Aktivitas ini memiliki kueri yang tersimpan dalam paket onSaveInstanceState(), dan harus meneruskan kueri tersebut ke ViewModel. ViewModel melihat bahwa hasil penelusuran belum disimpan ke cache, dan mendelegasikan pemuatan hasil penelusuran, menggunakan kueri penelusuran.
  • Aktivitas dibuat setelah perubahan konfigurasi. Aktivitas ini memiliki kueri yang tersimpan dalam paket onSaveInstanceState(), dan ViewModel telah menyimpan hasil penelusuran ke cache. Anda meneruskan kueri dari paket onSaveInstanceState() ke ViewModel, yang menentukan bahwa paket telah memuat data data yang diperlukan dan tidak perlu mengkueri ulang database.

Catatan: Saat aktivitas pertama kali dibuat, paket onSaveInstanceState() tidak berisi data dan objek ViewModel kosong. Saat membuat objek ViewModel, Anda meneruskan kueri kosong yang memberi tahu objek ViewModel bahwa belum ada data untuk dimuat. Oleh karena itu, aktivitas dimulai dalam status kosong.

Referensi lainnya

Untuk mempelajari lebih lanjut cara menyimpan status UI, lihat referensi berikut.

Blog