ViewModel için Kaydedilen Durum modülü Android Jetpack'in bir parçasıdır.
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, rotasyonlardaki veya diğer durumlarda durum hakkında endişelenmenize gerek yoktur. Ancak sistem tarafından başlatılan süreç ölümünü ele almanız gerekiyorsa yedek olarak SavedStateHandle
API'yi kullanabilirsiniz.
Kullanıcı arayüzü durumu genellikle etkinliklerde değil ViewModel
nesnelerinde depolanır veya buna referans verilir. Bu nedenle, onSaveInstanceState()
veya rememberSaveable
kullanımı, kayıtlı durum modülünün sizin için işleyebileceği bazı ortak metin gerektirir.
Bu modülü kullanırken ViewModel
nesneleri, oluşturucusu üzerinden bir SavedStateHandle
nesnesi alır. Bu nesne, kayıtlı durumlarla ilgili olarak nesne yazmanıza ve almanıza olanak tanıyan bir anahtar/değer eşlemesidir. Bu değerler, süreç sistem tarafından sonlandırıldıktan sonra kalıcı olur ve aynı nesne üzerinden kullanılabilir durumda kalır.
Kaydedilen durum görev yığınınıza bağlıdır. Görev yığınınız kaybolursa kayıtlı durumunuz da kaybolur. Bu durum, bir uygulamayı zorla durdururken, son kullanılanlar menüsünden kaldırırken veya cihazı yeniden başlatırken meydana gelebilir. Bu gibi durumlarda, görev yığını kaybolur ve bilgileri kayıtlı duruma geri yükleyemezsiniz. Kullanıcı tarafından başlatılan kullanıcı arayüzü durumu kapatma senaryolarında, kayıtlı durum geri yüklenmez. Sistem tarafından başlatılan senaryolarda böylesi yoktur.
Kurulum
Fragment 1.2.0 veya geçişli bağımlılığından (Etkinlik 1.1.0) başlayarak, ViewModel
için kurucu bağımsız değişkeni olarak SavedStateHandle
öğesini 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 yapılandırma gerekmeden ViewModel
örneğinizi alabilirsiniz. Varsayılan ViewModel
fabrikası, ViewModel
cihazınıza uygun SavedStateHandle
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 ViewModelProvider.Factory
örneği sağlarken AbstractSavedStateViewModelFactory
örneğini genişleterek SavedStateHandle
kullanımını etkinleştirebilirsiniz.
saveStateHandle ile çalışma
SavedStateHandle
sınıfı, set()
ve get()
yöntemleri aracılığıyla kayıtlı duruma gelen/kaydedilen durumdan veri yazıp almanıza olanak tanıyan bir anahtar/değer eşlemesidir.
SavedStateHandle
kullanıldığında, sorgu değeri işlem ölümü boyunca korunur. Böylece kullanıcının, etkinlik veya parçanın manuel olarak kaydedilmesi, geri yüklenmesi ve ViewModel
öğesine geri yönlendirilmesine gerek kalmadan, filtrelenen veri kümesini yeniden oluşturma işleminden önce ve sonra aynı şekilde görmesi sağlanır.
SavedStateHandle
, bir anahtar/değer eşleşmesiyle etkileşimde bulunurken bekleyebileceğiniz başka yöntemler de sunar:
contains(String key)
- Verilen anahtar için bir değer olup olmadığını kontrol eder.remove(String key)
- Belirli bir anahtarın değerini kaldırır.keys()
-SavedStateHandle
içindeki tüm anahtarları döndürür.
Ayrıca, gözlemlenebilir bir veri tutucu kullanarak SavedStateHandle
öğesinden değerler alabilirsiniz. Desteklenen türlerin listesi:
LiveData
getLiveData()
ile LiveData
gözlemlenebilirliğine sarmalanmış olan 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 girilmesi gibi kullanıcı etkileşimlerine ayarlanır. Bu güncellenen değer, daha sonra LiveData
dönüşümü 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); } }
Durum Akışı
getStateFlow()
ile StateFlow
gözlemlenebilirliğine sarmalanmış olan SavedStateHandle
değerlerini alın.
Anahtarın değerini güncellediğinizde StateFlow
yeni değeri alır. Çoğu zaman, bu değeri kullanıcı etkileşimleri (ör. bir veri listesini filtrelemek için sorgu girmek) nedeniyle de ayarlayabilirsiniz. Daha sonra, diğer Akış operatörlerini kullanarak bu güncellenmiş değeri dönüştürebilirsiniz.
Kotlin
class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { val filteredData: StateFlow<List<String>> = savedStateHandle.getStateFlow<String>("query") .flatMapLatest { query -> repository.getFilteredData(query) } fun setQuery(query: String) { savedStateHandle["query"] = query } }
Deneysel Compose'un Durum desteği
lifecycle-viewmodel-compose
yapısı, SavedStateHandle
ile Compose'un Saver
uygulamaları arasında birlikte çalışabilme olanağı sağlayan deneysel saveable
API'lerini sunar. Böylece, rememberSaveable
aracılığıyla özel bir Saver
ile kaydedebileceğiniz tüm State
öğeleri SavedStateHandle
ile de kaydedilebilir.
Kotlin
class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { var filteredData: List<String> by savedStateHandle.saveable { mutableStateOf(emptyList()) } fun setQuery(query: String) { withMutableSnapshot { filteredData += query } } }
Desteklenen türler
SavedStateHandle
içinde saklanan veriler Bundle
ile birlikte etkinlik veya parçanın savedInstanceState
geri kalanıyla birlikte kaydedilir ve geri yüklenir.
Doğrudan desteklenen türler
Varsayılan olarak, aşağıda gösterildiği gibi Bundle
ile aynı veri türleri için SavedStateHandle
üzerinde set()
ve get()
çağırabilirsiniz:
Tür/Sınıf desteği | Dizi desteği |
double |
double[] |
int |
int[] |
long |
long[] |
String |
String[] |
byte |
byte[] |
char |
char[] |
CharSequence |
CharSequence[] |
float |
float[] |
Parcelable |
Parcelable[] |
Serializable |
Serializable[] |
short |
short[] |
SparseArray |
|
Binder |
|
Bundle |
|
ArrayList |
|
Size (only in API 21+) |
|
SizeF (only in API 21+) |
Sınıf yukarıdaki listede yer alanlardan birine sahip değilse @Parcelize
Kotlin ek açıklamasını ekleyerek veya Parcelable
'ı doğrudan uygulayarak sınıfı ayrıştırılabilir hale getirebilirsiniz.
Ayrıştırılamayan sınıfları kaydetme
Bir sınıf Parcelable
veya Serializable
kullanmıyorsa ve bu arayüzlerden birini uygulamak için değiştirilemezse bu sınıfın bir örneğini SavedStateHandle
dosyasına doğrudan kaydetmek mümkün değildir.
Yaşam döngüsü 2.3.0-alpha03'ten itibaren SavedStateHandle
, setSavedStateProvider()
yöntemini kullanarak nesnenizi Bundle
olarak kaydedip geri yüklemek için kendi mantığınızı sağlayarak herhangi bir nesneyi kaydetmenize olanak tanır. SavedStateRegistry.SavedStateProvider
, kaydetmek istediğiniz durumu içeren bir Bundle
değeri döndüren tek bir saveState()
yöntemini tanımlayan arayüzdür. SavedStateHandle
durumunu kaydetmeye hazır olduğunda, SavedStateProvider
hizmetinden Bundle
öğesini almak için saveState()
yöntemini çağırır ve ilişkili anahtar için Bundle
değerini kaydeder.
ACTION_IMAGE_CAPTURE
niyetiyle kamera uygulamasından resim isteyen ve kameranın resmi depolaması gereken geçici bir dosya ileten bir uygulama örneğini düşünün. TempFileViewModel
, bu geçici dosyayı oluşturma mantığını içerir.
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; } }
İşlemin sonlandırılması ve daha sonra geri yüklenmesi halinde geçici dosyanın kaybolmadığından emin olmak için TempFileViewModel
, verilerinin kalıcı olmasını sağlamak üzere SavedStateHandle
kullanabilir. TempFileViewModel
adlı iş ortağının verilerini kaydetmesine izin vermek için SavedStateProvider
politikasını uygulayın ve ViewModel
öğesinin SavedStateHandle
öğesinde 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 SavedStateHandle
kaynağından temp_file
Bundle
kodunu alın. Bu, saveTempFile()
tarafından sağlanan Bundle
ile mutlak yolu içeren aynıdır. Daha sonra mutlak yol, yeni bir File
örneklendirmek 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; } } }
Testlerde KaydedilenStateHandle
SavedStateHandle
öğesini bağımlılık olarak alan bir ViewModel
test etmek için, gerektirdiği test değerleriyle yeni bir SavedStateHandle
örneği oluşturun ve bunu test ettiğiniz ViewModel
örneğine iletin.
Kotlin
class MyViewModelTest { private lateinit var viewModel: MyViewModel @Before fun setup() { val savedState = SavedStateHandle(mapOf("someIdArg" to testId)) viewModel = MyViewModel(savedState = savedState) } }
Ek kaynaklar
ViewModel
için Kaydedilen Durum modülü hakkında daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın.
Codelab uygulamaları
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken gösterilir
- Kullanıcı arayüzü durumlarını kaydetme
- Gözlemlenebilir veri nesneleriyle çalışma
- Bağımlılıkları olan ViewModel'ler oluşturma