ViewModel'e genel bakış   Android Jetpack'in bir parçasıdır.

Kotlin Multiplatform ile deneme
Kotlin Multiplatform, işletme mantığının diğer platformlarla paylaşılmasına olanak tanır. KMP'de ViewModel'i ayarlama ve ViewModel ile çalışma hakkında bilgi edinin.

ViewModel sınıfı, iş mantığı veya ekran düzeyinde durum tutucudur. Durumu kullanıcı arayüzüne sunar ve ilgili iş mantığını kapsar. Başlıca avantajı, durumu önbelleğe alması ve yapılandırma değişiklikleri boyunca kalıcı hale getirmesidir. Bu sayede, etkinlikler arasında gezinirken veya ekranı döndürme gibi yapılandırma değişikliklerinden sonra kullanıcı arayüzünüzün verileri tekrar getirmesi gerekmez.

Devlet görevlileri hakkında daha fazla bilgi için devlet görevlileri ile ilgili kılavuza bakın. Benzer şekilde, kullanıcı arayüzü katmanı hakkında daha fazla bilgi için Kullanıcı arayüzü katmanı ile ilgili yönergelere bakın.

ViewModel'in avantajları

ViewModel'e alternatif olarak, kullanıcı arayüzünüzde gösterdiğiniz verileri tutan düz bir sınıf kullanabilirsiniz. Bu durum, etkinlikler veya gezinme hedefleri arasında gezinirken sorun yaratabilir. Bunu yaparsanız kaydedilmiş örnek durumu mekanizmasını kullanarak saklamadığınız veriler yok edilir. ViewModel, bu sorunu çözen veri kalıcılığı için uygun bir API sağlar.

Alternatif olarak, Compose, saf durum tutucular için retain özellikleri sunar. Bu özellikler, ViewModel'in tam altyapısı olmadan düz sınıfların yapılandırma değişikliklerinden etkilenmemesini sağlar. Her iki mekanizma da durumun korunmasına yardımcı olsa da yaşam döngüleri ve temizleme davranışları farklı olduğundan genellikle bir ViewModel'i korunmuş bir örneğe sağlamak, bunun tersini yapmaktan daha güvenlidir.

ViewModel sınıfının temel avantajları esasen iki tanedir:

  • Kullanıcı arayüzü durumunu kalıcı hale getirmenizi sağlar.
  • İş mantığına erişim sağlar.

Kalıcı

ViewModel, hem ViewModel'in tuttuğu durum hem de ViewModel'in tetiklediği işlemler aracılığıyla kalıcılığa olanak tanır. Bu önbelleğe alma işlemi sayesinde, ekran döndürme gibi yaygın yapılandırma değişikliklerinde verileri tekrar getirmeniz gerekmez.

Kapsam

ViewModel'i örneklediğinizde, ViewModelStoreOwner arayüzünü uygulayan bir nesne iletirsiniz. Bu, bir gezinme hedefi, gezinme grafiği, etkinlik veya arayüzü uygulayan başka bir tür olabilir. Ayrıca, rememberViewModelStoreOwner API'sini kullanarak bir ViewModel'i doğrudan composable'a da kapsamlandırabilirsiniz. ViewModel'ınız daha sonra ViewModelStoreOwner Lifecycle'ına göre kapsamlandırılır. ViewModelStoreOwner kalıcı olarak kaldırılana kadar (ör. composable sahibi Composition'dan çıktığında) bellekte kalır.

Bir dizi sınıf, ViewModelStoreOwner arayüzünün doğrudan veya dolaylı alt sınıflarıdır. Doğrudan alt sınıflar ComponentActivity ve NavBackStackEntry'dır. Dolaylı alt sınıfların tam listesi için ViewModelStoreOwner referansına bakın. ViewModel'leri LazyList veya Pager içindeki tek tek öğelerle sınırlamak için rememberViewModelStoreProvider() işlevini kullanarak sahibi üst öğeye taşıyın.

Ana etkinliğin yapılandırması değiştiğinde, ViewModel'deki eşzamansız işlemler, etkinliğe veya belirli bir composable'a göre kapsamlandırılmış olsun ya da olmasın devam eder. Bu, azmin anahtarıdır.

Daha fazla bilgi için aşağıdaki ViewModel yaşam döngüsü bölümüne, ViewModel kapsamı belirleme API'leri'ne ve Jetpack Compose'daki durum yükseltme ile ilgili kılavuza bakın.

SavedStateHandle

SavedStateHandle, verileri yalnızca yapılandırma değişiklikleri sırasında değil, işlem sonlandırma sırasında da kalıcı hale getirmenizi sağlar. Yani, kullanıcı uygulamayı kapatıp daha sonra açsa bile kullanıcı arayüzü durumunu korumanızı sağlar.

Kullanıcı arayüzü durumunu kaydetme hakkında daha fazla bilgi için Compose'da kullanıcı arayüzü durumunu kaydetme başlıklı makaleyi inceleyin.

İş mantığına erişim

İş mantığının büyük çoğunluğu veri katmanında bulunsa da kullanıcı arayüzü katmanı da iş mantığı içerebilir. Bu durum, ekran kullanıcı arayüzü durumunu oluşturmak için birden fazla depodaki veriler birleştirildiğinde veya belirli bir veri türü için veri katmanı gerekmediğinde söz konusu olabilir.

ViewModel, kullanıcı arayüzü katmanındaki iş mantığını işlemek için doğru yerdir. ViewModel, etkinlikleri işlemeyle ve uygulama verilerini değiştirmek için iş mantığı uygulanması gerektiğinde bunları hiyerarşinin diğer katmanlarına devretmeyle de sorumludur.

ViewModel'i uygulama

Aşağıda, kullanıcının zar atmasına olanak tanıyan bir ekran için ViewModel'in örnek bir uygulaması verilmiştir.

data class DiceUiState(
    val firstDieValue: Int? = null,
    val secondDieValue: Int? = null,
    val numberOfRolls: Int = 0,
)

class DiceRollViewModel : ViewModel() {

    // Expose screen UI state
    private val _uiState = MutableStateFlow(DiceUiState())
    val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()

    // Handle business logic
    fun rollDice() {
        _uiState.update { currentState ->
            currentState.copy(
                firstDieValue = Random.nextInt(from = 1, until = 7),
                secondDieValue = Random.nextInt(from = 1, until = 7),
                numberOfRolls = currentState.numberOfRolls + 1,
            )
        }
    }
}

Ardından, ViewModel'e ekran düzeyinde bir composable'dan aşağıdaki gibi erişebilirsiniz:

import androidx.lifecycle.viewmodel.compose.viewModel

// Use the 'viewModel()' function from the lifecycle-viewmodel-compose artifact
@Composable
fun DiceRollScreen(
    viewModel: DiceRollViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    // Update UI elements
}

ViewModel ile coroutine'leri kullanma

ViewModel, Kotlin eş yordamları için destek içerir. Asenkron çalışmayı, kullanıcı arayüzü durumunu kalıcı hale getirdiği şekilde kalıcı hale getirebilir.

Daha fazla bilgi için Android Architecture Components ile Kotlin eş yordamlarını kullanma başlıklı makaleyi inceleyin.

ViewModel'ın yaşam döngüsü

Bir ViewModel'nin yaşam döngüsü doğrudan kapsamına bağlıdır. Bir ViewModel, kapsamının belirlendiği ViewModelStoreOwner ortadan kaybolana kadar bellekte kalır. Bu durum aşağıdaki bağlamlarda ortaya çıkabilir:

  • Etkinliklerde ise etkinlik bittiğinde.
  • Bir gezinme girişi, eski yığından kaldırıldığında
  • Bir composable'ın Composition'dan çıktığı durumda. rememberViewModelStoreOwner kullanarak bir ViewModel'i doğrudan kullanıcı arayüzünüzün rastgele bir bölümüne (ör. Pager veya LazyList) göre kapsamlandırabilirsiniz.

Bu nedenle, ViewModels, yapılandırma değişikliklerinden etkilenmeyen verileri depolamak için mükemmel bir çözümdür.

Şekil 1'de, bir etkinliğin rotasyona uğradıktan sonra tamamlanmasıyla ilgili çeşitli yaşam döngüsü durumları gösterilmektedir. Ayrıca, resimde ilişkili etkinlik yaşam döngüsünün yanında ViewModel'nin kullanım süresi de gösterilmektedir. Bu özel diyagram, bir etkinliğin durumlarını gösterir.

Bir ViewModel&#39;in yaşam döngüsünü, etkinlik durum değiştirdikçe gösterir.
Şekil 1. Bir etkinliğin ve ViewModel'in yaşam döngüsü durumları.

Genellikle sistem bir etkinlik nesnesinin onCreate() yöntemini ilk kez çağırdığında ViewModel isteğinde bulunursunuz. Sistem, bir etkinliğin varlığı boyunca onCreate() işlevini birkaç kez çağırabilir. Örneğin, cihaz ekranı döndürüldüğünde bu işlev çağrılır. ViewModel, ilk kez ViewModel istediğiniz andan etkinlik tamamlanıp yok edilene kadar var olur.

ViewModel bağımlılıklarını temizleme

ViewModel, ViewModelStoreOwner yaşam döngüsü sırasında yok edildiğinde onCleared yöntemini çağırır. Bu, ViewModel'in yaşam döngüsünü takip eden tüm işleri veya bağımlılıkları temizlemenizi sağlar.

Aşağıdaki örnekte viewModelScope için alternatif bir yöntem gösterilmektedir. viewModelScope, ViewModel'in yaşam döngüsünü otomatik olarak takip eden yerleşik bir CoroutineScope'dir. ViewModel, işlemleri tetiklemek için bunu kullanır. Daha kolay test için viewModelScope yerine özel bir kapsam kullanmak istiyorsanız ViewModel, oluşturucusunda bağımlılık olarak CoroutineScope alabilir. ViewModelStoreOwner yaşam döngüsünün sonunda ViewModel'i temizlediğinde ViewModel, CoroutineScope öğesini de iptal eder.

class MyViewModel(
    private val coroutineScope: CoroutineScope =
        CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
) : ViewModel() {

    // Other ViewModel logic ...

    override fun onCleared() {
        coroutineScope.cancel()
    }
}

Yaşam döngüsü 2.5 sürümü ve sonraki sürümlerde, ViewModel örneği temizlendiğinde otomatik olarak kapanan ViewModel'in oluşturucusuna bir veya daha fazla Closeable nesne iletebilirsiniz.

class CloseableCoroutineScope(
    context: CoroutineContext = SupervisorJob() + Dispatchers.Main.immediate
) : Closeable, CoroutineScope {
    override val coroutineContext: CoroutineContext = context
    override fun close() {
        coroutineContext.cancel()
   }
}

class MyViewModel(
    private val coroutineScope: CoroutineScope = CloseableCoroutineScope()
) : ViewModel(coroutineScope) {
    // Other ViewModel logic ...
}

En iyi uygulamalar

ViewModel'i uygularken izlemeniz gereken birkaç önemli en iyi uygulama aşağıda verilmiştir:

  • Kapsamları nedeniyle ViewModel'leri ekran düzeyinde bir durum bilgisi depolayıcının uygulama ayrıntıları olarak kullanın. Bunları, çip grupları veya formlar gibi yeniden kullanılabilir kullanıcı arayüzü bileşenlerinin durum tutucuları olarak kullanmayın. Aksi takdirde, her çip için açık bir görünüm modeli anahtarı kullanmadığınız sürece aynı ViewModelStoreOwner altındaki aynı kullanıcı arayüzü bileşeninin farklı kullanımlarında aynı ViewModel örneğini alırsınız.
  • ViewModel'ler, kullanıcı arayüzü uygulama ayrıntıları hakkında bilgi sahibi olmamalıdır. ViewModel API'nin sunduğu yöntemlerin ve kullanıcı arayüzü durumu alanlarının adlarını mümkün olduğunca genel tutun. Bu sayede ViewModel'iniz her türden kullanıcı arayüzünü (cep telefonu, katlanabilir telefon, tablet veya Chromebook) destekleyebilir.
  • ViewModel'lar, ViewModelStoreOwner'dan daha uzun süre yaşayabileceğinden bellek sızıntılarını önlemek için Context veya Resources gibi yaşam döngüsüyle ilgili API'lerin referanslarını tutmamalıdır.
  • ViewModel'leri diğer sınıflara, işlevlere veya diğer kullanıcı arayüzü bileşenlerine iletmeyin. Platform tarafından yönetildikleri için bunları platforma mümkün olduğunca yakın tutmanız gerekir. Örneğin, Etkinliğinize, ekran düzeyinde composable işlevinize veya gezinme hedefinize yakın tutabilirsiniz. Bu, alt düzey bileşenlerin ihtiyaç duyduklarından daha fazla veriye ve mantığa erişmesini engeller.

Daha fazla bilgi

Verileriniz karmaşıklaştıkça yalnızca verileri yüklemek için ayrı bir sınıf oluşturmayı tercih edebilirsiniz. ViewModel'ın amacı, verilerin yapılandırma değişikliklerinden etkilenmemesi için bir kullanıcı arayüzü denetleyicisine yönelik verileri kapsüllemektir. Yapılandırma değişikliklerinde verileri yükleme, kalıcı hale getirme ve yönetme hakkında bilgi edinmek için Kayıtlı kullanıcı arayüzü durumları başlıklı makaleyi inceleyin.

Android Uygulama Mimarisi Kılavuzu, bu işlevleri yönetmek için bir depo sınıfı oluşturmayı önerir.

Ek kaynaklar

ViewModel sınıfı hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.

Belgeler

İçeriği görüntüleme

Örnekler