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對象