ViewModel'e genel bakış Android Jetpack'in bir parçasıdır.
ViewModel
sınıfı, bir işletme mantığı veya ekran düzeyinde durum sahibidir. Durumu kullanıcı arayüzüne gösterir ve ilgili iş mantığını içerir.
En önemli avantajı, durumu önbelleğe alması ve yapılandırma değişiklikleriyle devam ettirebilmesidir. Böylece etkinlikler arasında gezinirken veya ekranı döndürme gibi yapılandırma değişikliklerini takip ederken kullanıcı arayüzünüzün tekrar veri getirmesi gerekmez.
Devlet sahipleri hakkında daha fazla bilgi için devlet sahipleri kılavuzunu inceleyin. Benzer şekilde, kullanıcı arayüzü katmanı hakkında genel olarak daha fazla bilgi edinmek için kullanıcı arayüzü katmanı kılavuzuna bakın.
ViewModel'in avantajları
ViewModel'in alternatifi, kullanıcı arayüzünüzde görüntülediğiniz verileri tutan düz bir sınıftır. Bu durum, etkinlikler veya Navigasyon hedefleri arasında gezinirken bir soruna dönüşebilir. Bu işlem, örnek durum mekanizmasını kullanarak depolamazsanız bu verileri yok eder. ViewModel, veri kalıcılığı için bu sorunu çözen kullanışlı bir API sunar.
ViewModel sınıfının temel avantajları temelde ikidir:
- Kullanıcı arayüzü durumunu korumanızı sağlar.
- İş mantığına erişim sağlar.
Kalıcı
ViewModel, hem bir ViewModel'in barındırdığı durum hem de bir ViewModel'in tetiklediği işlemler aracılığıyla kalıcılığa izin verir. Bu önbelleğe alma, ekran rotasyonu gibi yaygın yapılandırma değişiklikleriyle verileri tekrar getirmenize gerek olmadığı anlamına gelir.
Kapsam
Bir ViewModel'i örneklediğinizde, buna ViewModelStoreOwner
arayüzünü uygulayan bir nesne iletiyorsunuz. Bu bir Navigasyon hedefi, Gezinme grafiği, etkinlik, parça veya arayüzü uygulayan başka bir tür olabilir. Daha sonra ViewModel'iniz, ViewModelStoreOwner
Yaşam Döngüsü kapsamına alınır. ViewModelStoreOwner
kalıcı olarak ortadan kalkana kadar bellekte kalır.
Bir sınıf aralığı, ViewModelStoreOwner
arayüzünün doğrudan veya dolaylı alt sınıflarıdır. Doğrudan alt sınıflar: ComponentActivity
, Fragment
ve NavBackStackEntry
.
Dolaylı alt sınıfların tam listesi için ViewModelStoreOwner
referansına bakın.
ViewModel'in kapsamının aldığı parça veya etkinlik kaldırıldığında, eşzamansız çalışma, kapsamına alınan ViewModel'de devam eder. Kalıcılığın anahtarı budur.
Daha fazla bilgi için aşağıdaki ViewModel yaşam döngüsü ile ilgili bölüme bakın.
Kaydedilen Durum Tanımlayıcısı
SaveStateHandle, verileri yalnızca yapılandırma değişiklikleriyle değil, aynı zamanda işlem yeniden oluşturma yoluyla da tutmanıza olanak tanır. Yani, kullanıcı uygulamayı kapatıp daha sonra açtığında bile kullanıcı arayüzü durumunun değişmeden kalmasını sağlar.
İş mantığına erişim
İş mantığının büyük çoğunluğu veri katmanında bulunsa da kullanıcı arayüzü katmanı, iş mantığını da içerebilir. Bu durum, ekran kullanıcı arayüzü durumunu oluşturmak için birden fazla depodaki verileri birleştirirken veya belirli bir veri türünün veri katmanı gerektirmediği durumlarda geçerli olabilir.
ViewModel, kullanıcı arayüzü katmanında iş mantığını işlemek için doğru yerdir. ViewModel, etkinlikleri yönetmek ve uygulama verilerini değiştirmek için iş mantığının uygulanması gerektiğinde bunları hiyerarşinin diğer katmanlarına aktarmaktan da sorumludur.
Jetpack Compose
Jetpack Compose'u kullanırken ViewModel, ekran kullanıcı arayüzü durumunu oluşturduğunuz öğelerinize göstermenin birincil yöntemidir. Karma uygulamalarda, etkinlikler ve parçalar, oluşturulabileceğiniz işlevlerinizi barındırır. Bu, eski yaklaşımlardan bir değişim. Etkinlikler ve parçalarla yeniden kullanılabilir kullanıcı arayüzü parçaları oluşturmak, bu açıdan kullanıcı arayüzü denetleyicileri olarak çok daha aktif olmalarına neden olan basit ve sezgisel bir yaklaşım değildi.
ViewModel'i Compose ile birlikte kullanırken unutulmaması gereken en önemli nokta, bir ViewModel'in kapsamını derlenen bir öğeye ayarlayamayacağınızdır. Bunun nedeni, composable'ın
ViewModelStoreOwner
olmamasıdır. Bestedeki aynı kompozisyon öğesinin iki örneği veya aynı ViewModelStoreOwner
altında aynı ViewModel türüne erişen iki farklı beste öğesi, ViewModel'in aynı örneğini alır. Bu, genellikle beklenen davranış değildir.
Compose'da ViewModel'in avantajlarından yararlanmak için her ekranı bir Parça veya Etkinlik'te barındırın ya da Gezinme Oluştur'u kullanın ve ViewModel'leri Gezinme hedefine olabildiğince yakın şekilde, oluşturulmuş işlevlerde kullanın. Çünkü bir ViewModel'in kapsamını Gezinme hedeflerine, Gezinme grafiklerine, Etkinliklere ve Parçalara ayarlayabilirsiniz.
Daha fazla bilgi için Jetpack Compose'un eyalet kaldırma rehberini inceleyin.
ViewModel uygulama
Aşağıda, kullanıcının zar atabilmesini sağlayan bir ekran için ViewModel'in örnek uygulaması gösterilmektedir.
Kotlin
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,
)
}
}
}
Java
public class DiceUiState {
private final Integer firstDieValue;
private final Integer secondDieValue;
private final int numberOfRolls;
// ...
}
public class DiceRollViewModel extends ViewModel {
private final MutableLiveData<DiceUiState> uiState =
new MutableLiveData(new DiceUiState(null, null, 0));
public LiveData<DiceUiState> getUiState() {
return uiState;
}
public void rollDice() {
Random random = new Random();
uiState.setValue(
new DiceUiState(
random.nextInt(7) + 1,
random.nextInt(7) + 1,
uiState.getValue().getNumberOfRolls() + 1
)
);
}
}
Ardından, aşağıdaki şekilde bir etkinlikten ViewModel'e erişebilirsiniz:
Kotlin
import androidx.activity.viewModels
class DiceRollActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same DiceRollViewModel instance created by the first activity.
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
val viewModel: DiceRollViewModel by viewModels()
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
// Update UI elements
}
}
}
}
}
Java
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
DiceRollViewModel model = new ViewModelProvider(this).get(DiceRollViewModel.class);
model.getUiState().observe(this, uiState -> {
// update UI
});
}
}
Jetpack Compose
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 eş yordamları kullanma
ViewModel
, Kotlin eş yordamlarını destekler. Bu işlev, kullanıcı arayüzü durumunu koruduğu gibi eşzamansız çalışmayı da sürdürebilir.
Daha fazla bilgi için Android Mimari Bileşenleri ile Kotlin eş yordamlarını kullanma bölümüne bakın.
Bir ViewModel'in yaşam döngüsü
ViewModel
'in yaşam döngüsü, doğrudan kapsamına bağlıdır. ViewModel
, kapsama dahil edildiği ViewModelStoreOwner
kaybolana kadar bellekte kalır. Bu, aşağıdaki bağlamlarda gerçekleşebilir:
- Bir etkinlik söz konusu olduğunda, etkinlik tamamlandığında.
- Bir parçanın ayrılması durumunda.
- Bir Navigasyon girişi söz konusu olduğunda, bu giriş arka yığından kaldırıldığında.
Bu açıdan ViewModels, yapılandırma değişikliklerinden sonra dayanabilen verileri depolamak için mükemmel bir çözümdür.
Şekil 1'de, bir aktivitenin rotasyondan geçip bittiği sırada çeşitli yaşam döngüsü durumları gösterilmektedir. Bu çizimde, ilişkili etkinlik yaşam döngüsünün yanında ViewModel
'in kullanım ömrü de gösterilmektedir. Bu şemada bir etkinliğin durumları gösterilmektedir. Bir parçanın yaşam döngüsü için de aynı temel durumlar geçerlidir.
Sistem bir etkinlik nesnesinin onCreate()
yöntemini ilk kez çağırdığında genellikle bir ViewModel
isteğinde bulunursunuz. Sistem, bir etkinlik olduğunda (ör. cihaz ekranı döndürüldüğünde) onCreate()
'i birkaç kez çağırabilir. ViewModel
, ViewModel
için ilk istekte bulunmanızdan etkinlik bitip silinene kadar devam eder.
ViewModel bağımlılıklarını temizleme
ViewModelStoreOwner
, yaşam döngüsü içinde görünümü yok ettiğinde ViewModel onCleared
yöntemini çağırır. Bu sayede, ViewModel'in yaşam döngüsünü takip eden işleri veya bağımlılıkları temizleyebilirsiniz.
Aşağıdaki örnekte viewModelScope
yerine bir alternatif gösterilmektedir.
viewModelScope
, ViewModel'in yaşam döngüsünü otomatik olarak takip eden yerleşik bir CoroutineScope
'tir. ViewModel, işle ilgili işlemleri tetiklemek için bunu kullanır. Daha kolay test için viewModelScope
yerine özel bir kapsam kullanmak isterseniz ViewModel, oluşturucuda bağımlılık olarak bir 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ünden ve sonraki sürümlerde, ViewModel örneği temizlendiğinde otomatik olarak kapanan ViewModel oluşturucuya bir veya daha fazla Closeable
nesnesi aktarabilirsiniz.
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
Aşağıda, ViewModel'i uygularken izlemeniz gereken birkaç önemli en iyi uygulama verilmiştir:
- Kapsamları nedeniyle ViewModels'i ekran düzeyinde durum sahibinin uygulama ayrıntıları olarak kullanın. Bunları çip grupları veya formlar gibi yeniden kullanılabilir kullanıcı arayüzü bileşenlerinin eyalet sahipleri olarak kullanmayın. Aksi takdirde, aynı ViewModel örneğini, aynı ViewModelStoreOwner altında aynı kullanıcı arayüzü bileşeninin farklı kullanımlarında elde edersiniz.
- ViewModels, kullanıcı arayüzü uygulama ayrıntılarını bilmemelidir. ViewModel API'nin sunduğu yöntemlerin adlarını ve kullanıcı arayüzü durum alanlarının mümkün olduğunca genel adlarını koruyun. Bu şekilde, ViewModel'iniz her türlü kullanıcı arayüzünü barındırabilir: cep telefonu, katlanabilir, tablet, hatta Chromebook!
- ViewModels,
ViewModelStoreOwner
ürününden daha uzun süre dayanabileceğinden bellek sızıntılarını önlemek içinContext
veyaResources
gibi yaşam döngüsüyle ilgili API'lere referans içermemelidir. - ViewModel'leri diğer sınıflara, işlevlere veya diğer kullanıcı arayüzü bileşenlerine iletmeyin. Platform bunları yönettiği için onları mümkün olduğunca yakın bir yerde tutmalısınız. Etkinlik, parça veya ekran düzeyinde oluşturulabilen işlevinize yakın. Bu, alt düzey bileşenlerin ihtiyaç duyduğundan daha fazla veriye ve mantığa erişmesini önler.
Daha fazla bilgi
Verileriniz daha karmaşık hale geldikçe verileri yüklemek için ayrı bir sınıf kullanmayı tercih edebilirsiniz. ViewModel
'in amacı, verilerin yapılandırma değişikliklerinden etkilenmesini sağlamak için bir kullanıcı arayüzü denetleyicisine ait verileri kapsüllemektir. Yapılandırma değişiklikleri genelinde verileri yükleme, saklama ve yönetme hakkında bilgi edinmek için Kayıtlı Kullanıcı Arayüzü Durumları bölümüne bakın.
Android Uygulama Mimarisi Kılavuzu, bu işlevleri işlemek için bir depo sınıfı derlemeyi önerir.
Ek kaynaklar
ViewModel
sınıfı hakkında daha fazla bilgi edinmek için aşağıdaki kaynakları inceleyin.
Dokümanlar
- Kullanıcı arayüzü katmanı
- Kullanıcı Arayüzü Etkinlikleri
- Eyalet sahipleri ve kullanıcı arayüzü durumu
- Durum üretimi
- Veri katmanı
Sana Özel
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken gösterilir
- Yaşam döngüsüne duyarlı bileşenlerle Kotlin eş yordamlarını kullanma
- Kullanıcı arayüzü durumlarını kaydetme
- Sayfalı verileri yükleme ve görüntüleme