ViewModel için Kayıtlı Durum modülü Android Jetpack'in bir parçasıdır.

Şurada belirtildiği gibi: Kullanıcı Arayüzü Durumlarını Kaydetme, ViewModel nesne işleyebilir Bu nedenle, rotasyonlardaki durum konusunda endişelenmeniz gerekmez durumlar olabilir. Ancak, sistem tarafından başlatılan bir işlemi gerçekleştirmeniz ölüm durumunda SavedStateHandle API'yi yedek olarak kullanmak isteyebilirsiniz.

Kullanıcı arayüzü durumu genellikle ViewModel nesnelerde depolanır veya böyle bir duruma başvuruda bulunmaz etkinlikleri olduğundan, onSaveInstanceState() veya rememberSaveable kullanmak için kaydedilmiş durum modülünün size yardımcı olabilir.

Bu modülü kullanırken ViewModel nesne bir SavedStateHandle nesne 10-10 dakikadır. Bu nesne, bir anahtar/değer çiftinde ve kaydedilen duruma nesne yazma ve alma. Bu değerler işlem sistem tarafından sonlandırıldıktan sonra da devam eder ve kullanılabilir durumda kalır üzerinden geçeceğim.

Kayıtlı durum, görev yığınınıza bağlıdır. Görev yığınınız kaybolursa durumu da ortadan kalkar. Bu durum, uygulama zorla durdurulurken, uygulamasını kullanabilir veya cihazı yeniden başlatabilirsiniz. Böyle durumlarda görev yığını kaybolur ve bilgileri kayıtlı durumda geri yükleyemezsiniz. İçinde Kullanıcı tarafından başlatılan kullanıcı arayüzü durumunu kapatma durumlarda, kaydedilen durum geri yüklenmez. İçinde sistem tarafından başlatılan gerçeğe dönüşebilir.

Kurulum

Parça 1.2.0 ile başlar veya geçişli bağımlılığı Etkinlik 1.1.0, kabul edebilirsiniz ViewModel için kurucu bağımsız değişken olarak bir SavedStateHandle.

Kotlin

class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { ... }

Java

public class SavedStateViewModel extends ViewModel {
    private SavedStateHandle state;

    public SavedStateViewModel(SavedStateHandle savedStateHandle) {
        state = savedStateHandle;
    }

    ...
}

Daha sonra, başka herhangi bir ek olmadan ViewModel yapılandırma. Varsayılan ViewModel fabrika ayarı, uygun ViewModel cihazınıza SavedStateHandle.

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);

        ...


    }

    ...
}

Bir özel rapor sağlarken ViewModelProvider.Factory örneğin, bu kodu genişleterek SavedStateHandle kullanımını AbstractSavedStateViewModelFactory.

SavedStateHandle ile çalışma

SavedStateHandle sınıfı, yazma ve set() ve get() yöntemlerine göz atın.

SavedStateHandle kullanıldığında, sorgu değeri süreç bitimine kadar korunur. Böylece, kullanıcılara kampanya öncesinde ve sonrasında aynı filtrelenmiş veri kümesi gösterilir. etkinlikleri veya parçaları manuel olarak kaydetmenize, geri yüklemenize, ve bu değeri ViewModel içine geri yönlendirir.

SavedStateHandle, etkileşimde bulunurken bekleyebileceğiniz başka yöntemler de sunuyor bir anahtar/değer eşlemesi ile:

Ayrıca, SavedStateHandle etiketindeki değerleri bir gözlenebilir veri tutucusu. Desteklenen türlerin listesi:

ziyaret edin.

LiveData

SavedStateHandle öğesinden bir içine sarmalanmış değerleri alın LiveData kullanılarak gözlemlenebilir getLiveData(). Anahtarın değeri güncellendiğinde LiveData yeni değeri alır. En sık genellikle değer, kullanıcı etkileşimlerine bağlı olarak ayarlanır. Örneğin, veri listesini filtreleyebilirsiniz. Bu güncellenen değer, daha sonra Dönüştürme 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);
    }
}

Durum Akışı

SavedStateHandle öğesinden bir içine sarmalanmış değerleri alın StateFlow kullanılarak gözlemlenebilir getStateFlow(). Anahtarın değerini güncellediğinizde StateFlow yeni değeri alır. En sık değeri kullanıcı etkileşimlerine bağlı olarak ayarlayabilirsiniz. Örneğin, sorgu kullanabilirsiniz. Ardından, güncellenen bu değeri dönüştürebilirsiniz. Akış operatörlerini kullanın.

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 Oluşturma durumu desteği

lifecycle-viewmodel-compose yapısı, deneysel özellikleri sunar. saveable SavedStateHandle ile Compose'un arasında birlikte çalışabilirliğe olanak tanıyan API'ler Saver böylece State rememberSaveable aracılığıyla kaydedebilir özel bir Saver ile 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 ve savedInstanceState etkinliği veya parçayı ifade eder.

Doğrudan desteklenen türler

Varsayılan olarak, SavedStateHandle üzerinde set() ve get() adlı kişileri aşağıda gösterildiği gibi, Bundle ile aynı veri türleri:

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 alan onlardan birini uzatmıyorsa, @Parcelize ekleyerek ayrıştırılabilir sınıfı Kotlin ek açıklaması veya uygulama Doğrudan Parcelable.

Ayrıştırılamayan sınıfları kaydetme

Parcelable veya Serializable kullanmayan bir sınıf uygulamak üzere değiştirilmiş bir sürümünü kullanıyorsanız bu sınıfın bir örneğini doğrudan SavedStateHandle sınıfına kaydedebilir.

Şununla başlayan: Yaşam döngüsü 2.3.0-alpha03 SavedStateHandle, kendi nesnenizi sağlayarak herhangi bir nesneyi kaydetmenize olanak tanır sonraki adımları için şunları içerir: Bundle şunu kullanarak: setSavedStateProvider() yöntemidir. SavedStateRegistry.SavedStateProvider tek bir kodu tanımlayan bir saveState() yöntemi, kaydetmek istediğiniz durumu içeren bir Bundle döndürür. Zaman SavedStateHandle, durumunu kaydetmeye hazır. Çağrı: saveState() Bundle öğesini SavedStateProvider kaynağından alır ve İlişkili anahtar için Bundle.

Kamera uygulamasından görüntü isteyen bir uygulamaya örnek verelim. ACTION_IMAGE_CAPTURE (kameranın bu bilgiyi saklaması gereken yer için geçici bir dosya görüntüsüdür. TempFileViewModel, bu önerinin geçici bir dosyadır.

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ırsa geçici dosyanın kaybolmadığından emin olmak için ve daha sonra geri yüklenen TempFileViewModel, SavedStateHandle öğesini kullanarak şu işlemleri yapabilir: kullanmaya devam etmesini sağlar. TempFileViewModel uygulamasının verilerini kaydetmesine izin vermek için şunu uygula: SavedStateProvider ve şurada sağlayıcı olarak ayarlandı: SavedStateHandle 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;
        }
    }
}

Kullanıcı geri döndüğünde File verilerini geri yüklemek için temp_file öğesini alın SavedStateHandle arasında Bundle. Bu, Bundle tarafından sağlanan aynı Mutlak yolu içeren saveTempFile(). Bu durumda mutlak yol, yeni bir File örneği oluşturmak için kullanılır.

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 SavedStateHandle

Bağımlılık olarak SavedStateHandle alan bir ViewModel test etmek için gereken ve başarılı test değerlerine sahip yeni bir SavedStateHandle örneği bunu test ettiğiniz ViewModel örneğine gönderebilirsiniz.

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 Kayıtlı Durum modülü hakkında daha fazla bilgi için inceleyebilirsiniz.

Codelab'ler

ziyaret edin. ziyaret edin.