ViewModel'e genel bakış Android Jetpack'in bir parçasıdır.
ViewModel
sınıfı, bir iş mantığı veya ekran düzeyinde durum tutucudur. 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 bunu sürdürmesidir. Bu sayede, etkinlikler arasında gezinirken veya yapılandırma değişikliklerini (ör. ekranı döndürmek) takip ederken kullanıcı arayüzünün tekrar veri getirmesi gerekmez.
Eyalet sahipleri hakkında daha fazla bilgi için eyalet sahipleriyle ilgili kılavuzu inceleyin. Benzer şekilde, genel olarak kullanıcı arayüzü katmanı hakkında 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ünde görüntülediğiniz verileri barındıran düz bir sınıftır. Bu, etkinlikler veya Navigasyon hedefleri arasında gezinirken bir soruna neden olabilir. Bu işlem, örnek kaydetme durum mekanizmasını kullanarak depolamadığınız verileri kaldırır. 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 sahip olduğu durum hem de bir ViewModel'in tetiklediği işlemler aracılığıyla kalıcılığa olanak tanır. Bu önbelleğe alma, ekran döndürme gibi yaygın yapılandırma değişiklikleri aracılığıyla verileri tekrar getirmenize gerek olmadığı anlamına gelir.
Kapsam
ViewModel'i örneklendirdiğinizde ona ViewModelStoreOwner
arayüzünü uygulayan bir nesne iletirsiniz. Bu bir Gezinme hedefi, gezinme grafiği, etkinlik, parça veya arayüzü uygulayan başka bir tür olabilir. ViewModel'iniz daha sonra ViewModelStoreOwner
öğesinin Yaşam Döngüsü olarak ayarlanır. Uygulama, ViewModelStoreOwner
kalıcı olarak kaldırılana kadar bellekte kalır.
Çeşitli sınıflar, ViewModelStoreOwner
arayüzünün doğrudan veya dolaylı alt sınıflarıdır. Doğrudan alt sınıflar şunlardır: ComponentActivity
, Fragment
ve NavBackStackEntry
.
Dolaylı alt sınıfların tam listesi için ViewModelStoreOwner
referansına bakın.
ViewModel'in kapsamının ayarlandığı parça veya etkinlik kaldırıldığında, kapsama alınan ViewModel'de eşzamansız çalışma 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.
SavedStateHerkese Açık
SavedStateHandle, verileri yalnızca yapılandırma değişiklikleriyle değil, aynı zamanda süreç yeniden oluşturma yoluyla korumanıza olanak tanır. Diğer bir deyişle, 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 mevcut olsa da, kullanıcı arayüzü katmanı aynı zamanda iş mantığını da içerebilir. Bu durum, ekran kullanıcı arayüzü durumu oluşturmak için birden fazla depodan veri birleştirildiğinde veya belirli bir veri türünün veri katmanı gerektirmediği durumlarda geçerli olabilir.
ViewModel, kullanıcı arayüzü katmanındaki iş mantığını işlemek için doğru yerdir. ViewModel, uygulama verilerini değiştirmek için iş mantığının uygulanması gerektiğinde etkinlikleri işlemekten ve hiyerarşinin diğer katmanlarına yetki vermekten de sorumludur.
Jetpack Compose
Jetpack Compose'u kullanırken ViewModel, ekran kullanıcı arayüzü durumunu composable'larınıza göstermenin birincil yoludur. Karma bir uygulamada, etkinlikler ve parçalar yalnızca composable işlevlerinizi barındırır. Bu, eski yaklaşımlardan değişiyor. Etkinlikler ve parçalarla yeniden kullanılabilir kullanıcı arayüzü parçaları oluşturmanın o kadar basit ve sezgisel olmadığı, bu yüzden de kullanıcı arayüzü denetleyicileri olarak çok daha etkin olmalarını sağladı.
ViewModel'i Compose ile kullanırken unutulmaması gereken en önemli nokta, bir ViewModel'in kapsamını bir composable'a ayarlayamayacağınızdır. Bunun nedeni, bir composable'ın ViewModelStoreOwner
olmamasıdır. Bestede aynı composable'ın iki örneği veya aynı ViewModelStoreOwner
altında aynı ViewModel türüne erişen iki farklı composable, 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 ve ViewModelleri'ni Gezinme hedefine mümkün olduğunca yakın olan composable işlevlerde kullanın. Bunun nedeni, bir ViewModel'i Gezinme hedeflerine, Gezinme grafiklerine, Etkinliklere ve Parçalara dahil edebilmenizdir.
Daha fazla bilgi için Jetpack Compose için eyalet kaldırma rehberine bakın.
ViewModel Uygulama
Aşağıda, kullanıcının zar atmasına izin veren bir ekran için ViewModel uygulamasına bir örnek verilmiştir.
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
)
);
}
}
Daha sonra, ViewModel'e bir etkinlikten aşağıdaki şekilde 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. Eşzamansız çalışmayı kullanıcı arayüzü durumunda olduğu gibi sürdürebilir.
Daha fazla bilgi için Android Mimari Bileşenleri ile Kotlin eş yordamlarını kullanma konusuna bakın.
ViewModel'in yaşam döngüsü
Bir ViewModel
'nın yaşam döngüsü doğrudan onun kapsamına bağlıdır. ViewModel
öğesi, kapsama dahil olduğu 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ça durumunda, ayrıldığında.
- Gezinme girişi olması durumunda, söz konusu giriş arka yığından kaldırıldığında.
Bu da ViewModels'i yapılandırma değişikliklerinden korkan verilerin depolanması için mükemmel bir çözüm haline getirir.
Şekil 1'de, bir etkinlik rotasyona tabi tutulup biten çeşitli yaşam döngüsü durumları gösterilmektedir. Resimde, ilişkilendirilmiş etkinlik yaşam döngüsünün yanında ViewModel
kullanım ömrü de gösterilmektedir. Bu özel şema, bir etkinliğin durumunu gösterir. Bir parçanın yaşam döngüsü için de aynı temel durumlar geçerlidir.
Genellikle sistem, bir etkinlik nesnesinin onCreate()
yöntemini ilk kez çağırdığında ViewModel
isteğinde bulunursunuz. Sistem, bir etkinlik devam ederken (ör. cihaz ekranı döndürüldüğünde) onCreate()
numarasını birkaç kez çağırabilir. ViewModel
, ilk ViewModel
isteğinde bulunduğunuz andan etkinlik tamamlanıp kaldırılana kadar kullanımda kalır.
ViewModel bağımlılıklarını temizleme
ViewModel, ViewModelStoreOwner
tarafından yaşam döngüsü içinde kaldırıldığında onCleared
yöntemini çağırır. Böylece ViewModel'in yaşam döngüsünü takip eden tüm işleri veya bağımlılıkları temizleyebilirsiniz.
Aşağıdaki örnekte viewModelScope
için bir alternatif gösterilmektedir.
viewModelScope
, ViewModel'in yaşam döngüsünü otomatik olarak takip eden yerleşik bir CoroutineScope
öğesidir. 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şturucusuna bir 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ü sürüm 2.5 ve sonraki sürümlerinden, ViewModel örneği temizlendiğinde otomatik olarak kapanan ViewModel oluşturucusuna 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
ViewModel'i uygularken izlemeniz gereken bazı temel en iyi uygulamalar şunlardır:
- Kapsamları nedeniyle, ViewModelleri bir ekran düzeyi durumu sahibinin uygulama ayrıntıları olarak kullanın. Bunları çip grupları veya formlar gibi yeniden kullanılabilir kullanıcı arayüzü bileşenlerinin durum sahipleri olarak kullanmayın. Aksi takdirde, çip başına açık bir görünüm modeli anahtarı kullanmadıkça, aynı ViewModelStoreOwner altında 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 adlarını ve kullanıcı arayüzü durum alanlarının adlarını mümkün olduğunca genel tutun. Bu şekilde, ViewModel'iniz her türlü kullanıcı arayüzünü kullanabilir: cep telefonu, katlanabilir cihaz, tablet, hatta Chromebook!
- ViewModelleri,
ViewModelStoreOwner
cihazından daha uzun süre dayanabileceğinden, bellek sızıntılarını önlemek içinContext
veyaResources
gibi yaşam döngüsüyle alakalı API referanslarını tutmamalıdır. - ViewModelleri başka sınıflara, işlevlere veya diğer kullanıcı arayüzü bileşenlerine geçirmeyin. Platform bunları yönettiği için bunları mümkün olduğunca birbirine yakın tutmalısınız. Etkinlik, parça veya ekran düzeyinde composable işlevinize yakın bir yerde. Bu, alt düzey bileşenlerin ihtiyaç duyduklarından daha fazla veriye ve mantığa erişmesini önler.
Daha fazla bilgi
Verileriniz daha karmaşık hale geldikçe yalnızca verileri yüklemek için ayrı bir sınıf oluşturmayı seçebilirsiniz. ViewModel
'ın amacı, verilerin yapılandırma değişikliklerinden etkilenmemesi için kullanıcı arayüzü denetleyicisine yönelik verileri kapsüllemektir. Yapılandırma değişiklikleri genelinde verileri yükleme, kalıcı hale getirme 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'nda, bu işlevlerin işlenmesi için bir depo sınıfının oluşturulması önerilir.
Ek kaynaklar
ViewModel
sınıfı hakkında daha fazla bilgi için aşağıdaki kaynaklara başvurun.
Dokümanlar
- Kullanıcı arayüzü katmanı
- Kullanıcı Arayüzü Etkinlikleri
- Durum sahipleri ve Kullanıcı Arayüzü Durumu
- Eyalet üretimi
- Veri katmanı
Numuneler
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Yaşam döngüsüne duyarlı bileşenlerle Kotlin eş yordamlarını kullanma
- Kullanıcı arayüzü durumlarını kaydet
- Sayfalandırılmış verileri yükleme ve görüntüleme