ViewModel nasıl hayatta kalıyor?

Mohammad Khakpaki
Appcent
Published in
3 min readMar 6, 2024

MVVM ( Model-View-ViewModel) mimarisi son zamanlarda android uygulamaların varsayılan mimarisi haline geldi ve hepimiz öyle yada böyle Android uygulamalarımızda ViewModel kullanıyoruz.

Peki hiç merak ettiniz mi nasıl oluyor da bu ViewModel dediğimiz class’lar activity’nin configuration değişikliklerinde hayatta kalmayı başarıyorlar?

Gelin bu sorunun cevabına birlikte bakalım.

Aradığımız sorunun cevabını bula bilmek için bu süreçte aktif olan tüm class’ları bir gözden geçirelim

ViewModel

Bu class’ta view tarafıyla ilgili bilgileri saklıyoruz, ViewState yada View’da gösterilecek datalar gibi.

ViewModelStore

Normalde her activity ya fragment’ta bir adet ViewModel kullanıyoruz ama aslında bir View’a bağlı birden fazla ViewModel ola biliyor ve bu ViewModelleri bir yerde kaydetmemiz gerekiyor, o yerin adı ViewModelStore.

public class ViewModelStore {

private final HashMap<String, ViewModel> mMap = new HashMap<>();

final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}

final ViewModel get(String key) {
return mMap.get(key);
}

Set<String> keys() {
return new HashSet<>(mMap.keySet());
}

/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}

kısacası bir view’nun ViewModellerini bir hashmap’te kaydediyor.

ViewModelStoreOwner

Kısacası ViewModeli olan ve lifecycle’ı olan her view bir ViewModelStoreOwner oluyor ama gelin daha detaylı bakalım.

public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}

Normalde bu sadece bir interface ve ViewModeli olan viewlar bu interfacei kullanmak zorunda.

Daha önce bahsettiğimiz ViewModelStore activitynin configuration changelerinden korunmuyor.

Peki ViewModel nasıl hayatta kalıyor?

Şu ana kadar ViewModel, ViewModelStore ve ViewModelStoreOwner classlar’ını tanıdık gelin şimdi bunlar nasıl bir birine bağlanıp ve ViewModelin hayatını kurtarıyor ona bakalım.

ViewModelStore ları kurtarmak görevi ViewModelStoreOwner interfaceini implement eden class a ait. O yüzden bu interfacei kullanan her class kendi doğru bildiği şekilde ViewModelStore’u Configuration değişikliklerinden koruma garantisi vermek zoruna.

Örnek olarak eğer AppCompatActivity nin koduna bakarsanız onun bu ViewModelStoreOwner u bu şekilde implement ettiğini göreceksiniz.

@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
ensureViewModelStore();
return mViewModelStore;
}
    void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}

Burada ViewModelStore u kurtarmak için ativity NonConfigurationInstances’i kullanıyor.

Ama nedir bu NonConfigurationInstances?

Çok basıt AppCompatActivitynin kendi içinde tanımladığı bir static class:

static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}

ve getLastNonConfigurationInstance activitye ait bir method olup ve Object ile çalıştığı için burada AppCompatActivity bahsi geçen static classe cast edip ve onunla kaydediyor.

ve bahsi geçen onRetainNonConfigurationInstance ise bu şekilde:

@Override
@Nullable
@SuppressWarnings("deprecation")
public final Object onRetainNonConfigurationInstance() {
// Maintain backward compatibility.
Object custom = onRetainCustomNonConfigurationInstance();

ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}

if (viewModelStore == null && custom == null) {
return null;
}

NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}

ve bu satırda daha önceki instance te viewModelStore varsa direkt onu kullanıyoruz.

NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}

Akılda kalan tek soru var:

Peki bu ViewModelStoreOwner ne zaman ViewModelStore ları temizlemeyi nereden anlıyor?

Bu sorunun cevabı içinde yine AppCompatActivity init methoduna bakarsak böyle bir observer göreceğiz

getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});

Bu observerda Activity eğer onDestroy configuration change ile ilgili değilse ViewModelStore u temizliyor ama diğer durumlarda store u korumaya devam ediyor.

Umarım bu yazıyı okuduktan sonra ViewModel içindeki stateler nasıl configuration changelerde hayatta kalıyor hakkında daha detaylı bilgi edinmişsinizdir.

--

--