ViewModel için Kayıtlı Durum modülü (Görünümler) Android Jetpack'in bir parçasıdır.
Kavramlar ve Jetpack Compose uygulaması
Kullanıcı Arayüzü Durumlarını Kaydetme bölümünde belirtildiği gibi, ViewModel nesneleri yapılandırma değişikliklerini işleyebilir. Bu nedenle, döndürme veya diğer durumlarda durumla ilgili endişelenmenize gerek yoktur. Ancak sistem tarafından başlatılan süreç sonlandırmalarını işlemeniz gerekiyorsa yedek olarak SavedStateHandle API'sini kullanabilirsiniz.
Kullanıcı arayüzü durumu genellikle ViewModel nesnelerinde depolanır veya bunlara referans verilir ve etkinliklerde depolanmaz. Bu nedenle, onSaveInstanceState() kullanmak için kaydedilmiş durum modülünün sizin için işleyebileceği bazı standart kodlar gerekir.
Bu modül kullanılırken ViewModel nesneleri, oluşturucusu aracılığıyla SavedStateHandle nesnesi alır. Bu nesne, kaydedilmiş duruma nesne yazmanıza ve nesne almanıza olanak tanıyan bir anahtar/değer çifti haritasıdır. Bu değerler, işlem sistem tarafından sonlandırıldıktan sonra da kalıcı olur ve aynı nesne üzerinden kullanılmaya devam eder.
Kaydedilen durum, görev yığınına bağlıdır. Görev yığınınız kaybolursa kaydedilen durumunuz da kaybolur. Bu durum, bir uygulama zorla durdurulduğunda, uygulamayı son kullanılanlar menüsünden kaldırdığınızda veya cihazı yeniden başlattığınızda ortaya çıkabilir. Bu gibi durumlarda görev yığını kaybolur ve kaydedilen durumdaki bilgileri geri yükleyemezsiniz. Kullanıcı tarafından başlatılan kullanıcı arayüzü durumunu kapatma senaryolarında, kaydedilen durum geri yüklenmez. Sistem tarafından başlatılan senaryolarda bu durum geçerlidir.
Kurulum
Fragment 1.2.0 veya geçişli bağımlılığı Activity 1.1.0'dan itibaren, SavedStateHandle öğesini ViewModel öğenizin oluşturucu bağımsız değişkeni olarak kabul edebilirsiniz.
Kotlin
class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { ... }
Java
public class SavedStateViewModel extends ViewModel { private SavedStateHandle state; public SavedStateViewModel(SavedStateHandle savedStateHandle) { state = savedStateHandle; } ... }
Ardından, ek bir yapılandırma yapmadan ViewModel örneğini alabilirsiniz. Varsayılan ViewModel fabrikası, ViewModel için uygun SavedStateHandle değerini sağlar.
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); ... } ... }
Özel bir ViewModelProvider.Factory örneği sağlarken SavedStateHandle kullanımını AbstractSavedStateViewModelFactory'ı genişleterek etkinleştirebilirsiniz.
SavedStateHandle ile çalışma
SavedStateHandle sınıfı, set() ve get() yöntemleriyle kaydedilmiş durumdan veri yazmanıza ve veri almanıza olanak tanıyan bir anahtar/değer eşlemesidir.
SavedStateHandle kullanıldığında sorgu değeri, işlem sonlandığında korunur. Böylece, etkinlik veya parçanın bu değeri manuel olarak kaydetmesi, geri yüklemesi ve SavedStateHandle'ya geri iletmesi gerekmeden, kullanıcı yeniden oluşturmadan önce ve sonra aynı filtrelenmiş veri grubunu görür.ViewModel
SavedStateHandle ayrıca bir anahtar/değer çifti haritasıyla etkileşimde bulunurken bekleyebileceğiniz başka yöntemler de içerir:
contains(String key): Belirli bir anahtar için değer olup olmadığını kontrol eder.remove(String key): Belirli bir anahtarın değerini kaldırır.keys():SavedStateHandleiçinde bulunan tüm anahtarları döndürür.
Ayrıca, gözlemlenebilir bir veri tutucu kullanarak SavedStateHandle değerlerini de alabilirsiniz. Desteklenen türlerin listesi:
LiveData
getLiveData() kullanarak LiveData
observable'a sarılmış SavedStateHandle değerlerini alın. Anahtarın değeri güncellendiğinde LiveData yeni değeri alır. Değer genellikle, bir veri listesini filtrelemek için sorgu girme gibi kullanıcı etkileşimleri nedeniyle ayarlanır. Bu güncellenen değer daha sonra dönüşüm LiveData için kullanılabilir.
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); } }
Desteklenen türler
SavedStateHandle içinde tutulan veriler, etkinliğin veya parçanın geri kalanı olan savedInstanceState ile birlikte Bundle olarak kaydedilir ve geri yüklenir.
Paketlenebilir olmayan sınıfları kaydetme
Bir sınıf Parcelable veya Serializable uygulamıyorsa ve bu arayüzlerden birini uygulayacak şekilde değiştirilemiyorsa bu sınıfın bir örneğini doğrudan SavedStateHandle içine kaydetmek mümkün değildir.
Lifecycle 2.3.0-alpha03'ten itibaren SavedStateHandle, setSavedStateProvider() yöntemini kullanarak nesnenizi Bundle olarak kaydetme ve geri yükleme mantığınızı sağlayarak herhangi bir nesneyi kaydetmenize olanak tanır.
SavedStateRegistry.SavedStateProvider, kaydetmek istediğiniz durumu içeren bir Bundle döndüren tek bir saveState() yöntemini tanımlayan bir arayüzdür. SavedStateHandle durumu kaydetmeye hazır olduğunda saveState() işlevini çağırarak SavedStateProvider içindeki Bundle değerini alır ve ilişkili anahtar için Bundle değerini kaydeder.
Kamera uygulamasından ACTION_IMAGE_CAPTURE intent'i aracılığıyla resim isteyen bir uygulamayı ele alalım. Bu uygulama, kameranın resmi depolayacağı yer için geçici bir dosya gönderir. TempFileViewModel, bu geçici dosyayı oluşturma mantığını kapsar.
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; } }
Etkinliğin işlemi sonlandırılıp daha sonra geri yüklenirse geçici dosyanın kaybolmaması için TempFileViewModel, verilerini kalıcı hale getirmek üzere SavedStateHandle kullanabilir. TempFileViewModel uygulamasının verilerini kaydetmesine izin vermek için SavedStateProvider uygulayın ve ViewModel uygulamasının SavedStateHandle üzerinde sağlayıcı olarak ayarlayın:
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; } } }
Kullanıcı geri döndüğünde File verilerini geri yüklemek için temp_file
Bundle değerini SavedStateHandle konumundan alın. Bu, mutlak yolu içeren saveTempFile() tarafından sağlanan Bundle ile aynıdır. Daha sonra mutlak yol, yeni bir File oluşturmak için kullanılabilir.
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; } } }
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- Kullanıcı arayüzü durumlarını kaydetme
- Gözlemlenebilir veri nesneleriyle çalışma
- Bağımlılıklarla ViewModel oluşturma