天天看點

ViewModel源碼分析ViewModel源碼分析

ViewModel源碼分析

學習過ViewModel的都知道,ViewModel主要對資料進行存儲維護,當在異常情況下(橫豎屏)Activity被銷毀的時候恢複資料。

Android異常情況下維護資料的方法

  • Activity.onSaveInstanceState和Activity.onRestoreInstanceState
  • FragmentActivity.onRetainNonConfigurationInstance和FragmentActivity.getLastNonConfigurationInstance
  • Fragment.setRetainInstance()的特性

在Android中想要維護異常銷毀Activity都是通過以上三種方法,因為方法一需要序列化的緣故,大資料的資料恢複我們一般用後面兩種方法,了解了這些簡單的知識點後,接下來我們來看看ViewModel的源碼。

FragmentActivity儲存和恢複資料的流程

讓我們先來看看擷取ViewModel的入口代碼:

1.FragmentActivity
    final ProjectViewModel viewModel = ViewModelProviders.of(this, viewModelFactory)
            .get(ProjectViewModel.class);
	
	2.ViewModelProviders
	public static ViewModelProvider of(@NonNull FragmentActivity activity,
        	@Nullable Factory factory) {
    	...
    	return new ViewModelProvider(activity.getViewModelStore(), factory);
	}
           

代碼塊1使用ViewModelProviders.of靜态方法建立ViewModelProvider的對象,這裡我們先不考慮activity.getViewModelStore()的邏輯,繼續看下去,然後調用其ViewModelProvider.get方法:

public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
   	...
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
	1.從ViewModelStore擷取ViewModel
    ViewModel viewModel = mViewModelStore.get(key);

    if (modelClass.isInstance(viewModel)) {
        2.取出的對象不為null 并且 為 傳入的Class直接傳回
        return (T) viewModel;
    } else {
        ..
    }
	3.在工廠類中擷取到新的ViewModel對象,并儲存在ViewModelStor中
    viewModel = mFactory.create(modelClass);
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}
           

以上擷取ViewModel的流程我們可以總結為:

  • 先嘗試從ViewModelStore根據相關的Key擷取到ViewModel對象
  • 假如能夠擷取到,并且是我們需要的對象則直接傳回
  • 假如不能擷取到,那麼就使用工廠類建立新的ViewModel對象,并且儲存到ViewModelStore中維護

到這裡我們可以嘗試着看看ViewModelStore是一個什麼類?

public class ViewModelStore {
	private final HashMap<String, ViewModel> mMap = new HashMap<>();
	final void put(String key, ViewModel viewModel) {
    	...
	}
	final ViewModel get(String key) {
    	...
	}
	public final void clear() {
    	...
	}
}
           

從類名我們就可以看出來,這個類的功能主要是:為了存儲ViewModel,其内部核心就是使用HashMap對ViewModel進行管理,其對象的擷取辦法我們回到上面的 ViewModelProviders.of() 檢視:activity.getViewModelStore()

public ViewModelStore getViewModelStore() {
    if (getApplication() == null) {
        ...
    }
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}
           

從上面的代碼片段我們可以看出大緻的邏輯流程為:

  • 判斷假如ViewModelStore為空,那麼就從FragmentActivity.getLastNonConfigurationInstance擷取NonConfigurationInstances對象,然後擷取到儲存的ViewModelStore
  • 否則直接傳回ViewModelStore對象

以上就是擷取ViewModelStore的流程,既然有恢複資料的流程,那麼就要看一下儲存資料的流程,儲存資料的按照原理是在FragmentActivity

.onRetainNonConfigurationInstance()中:

public final Object onRetainNonConfigurationInstance() {
    ...
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = mViewModelStore;
    nci.fragments = fragments;
    return nci;
}
           

從代碼中可知,當出現異常情況銷毀時onRetainNonConfigurationInstance()方法會被調用儲存資料對象,然後在FragmentActivity.getLastNonConfigurationInstance被調用的時候進行恢複資料。

最終當Activity進行銷毀時會調用FragmentActivity.onDestroy()方法,假如目前不是螢幕滾動導緻的銷毀,那麼ViewModelStore會被清理資源:

protected void onDestroy() {
    super.onDestroy();
    if (mViewModelStore != null && !isChangingConfigurations()) {
        mViewModelStore.clear();
    }

}
           

Fragment

Fragment的原理稍微簡單點,其實就是直接建立ViewModelStore對象進行維護ViewModel,利用Fragment.setRetainInstance()的特性讓在Fragment的ViewModelStore對象在Activity橫豎屏翻滾的時候不進行回收對象的處理

Factory類

public interface Factory {
    @NonNull
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
           

Factory類是一個對象,定義了建立ViewModel的協定接口,ViewModel架構提供了兩個實作類NewInstanceFactory和AndroidViewModelFactory,使用的是Class反射建立對象。

總結

  • Activity使用FragmentActivity.onRetainNonConfigurationInstance和FragmentActivity.getLastNonConfigurationInstance的特性進行儲存和恢複資料
  • Fragment使用Fragment.setRetainInstance()的特性進行儲存和恢複資料
  • ViewModelStore的作用是維護ViewModel對象
  • Factory工廠類的作用是産生ViewModel對象

繼續閱讀