Android ViewModel原始碼解析
ViewModel 是 Android 架構元件之一,用於分離 UI 邏輯與 UI 資料。在發生 Configuration Changes 時,它不會被銷燬。在介面重建後,方便開發者呈現介面銷燬前的 UI 狀態。
主要類

ViewModel主要類圖.png
-
ViewModel
ViewModel 是一個抽象類,只定義了一個空的 onCleared()方法。
AndroidViewModel 類擴充套件了 ViewModel 類,增加了Application 欄位,在構造方法初始化,並提供了 getApplication() 方法。
public abstract class ViewModel { protected void onCleared() { } } // AndroidViewModel繼承ViewModel,持有Application public class AndroidViewModel extends ViewModel { private Application mApplication; public AndroidViewModel(@NonNull Application application) { mApplication = application; } public <T extends Application> T getApplication() { return (T) mApplication; } }
-
ViewModelProviders
ViewModelProviders 類提供了4個靜態工廠方法 of() 建立一個新的 ViewModelProvider 物件。
public class ViewModelProviders { public static ViewModelProvider of(@NonNull Fragment fragment) { return of(fragment, null); } public static ViewModelProvider of(@NonNull FragmentActivity activity) { return of(activity, null); } public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) { Application application = checkApplication(checkActivity(fragment)); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(fragment.getViewModelStore(), factory); } public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { Application application = checkApplication(activity); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(activity.getViewModelStore(), factory); }
-
ViewModelProvider
ViewModelProvider 負責提供 ViewModel 物件
public class ViewModelProvider { private final Factory mFactory; private final ViewModelStore mViewModelStore; //獲取一個ViewModel物件,如果存在直接返回,不存在建立 public <T extends ViewModel> T get(@NonNull Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null) { throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels"); } return get(DEFAULT_KEY + ":" + canonicalName, modelClass); } //從ViewModelStore中獲取ViewModel public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) { ViewModel viewModel = mViewModelStore.get(key); if (modelClass.isInstance(viewModel)) { //noinspection unchecked return (T) viewModel; } else { //noinspection StatementWithEmptyBody if (viewModel != null) { // TODO: log a warning. } } viewModel = mFactory.create(modelClass); mViewModelStore.put(key, viewModel); //noinspection unchecked return (T) viewModel; }
-
Factory
建立ViewModel工廠的介面類
public interface Factory { <T extends ViewModel> T create(@NonNull Class<T> modelClass); }
-
ViewModelStore
使用Map儲存當前頁面已存在的ViewModel
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); } public final void clear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } }
ViewModelStore 是來自於 FragmentActivity 和 Fragment,它們實現了 ViewModelStoreOwner 介面,返回當前 UI 作用域裡的 ViewModelStore 物件。
public ViewModelStore getViewModelStore() { if (getContext() == null) { throw new IllegalStateException("Can't access ViewModels from detached fragment"); } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } return mViewModelStore; } public void onDestroy() { mCalled = true; FragmentActivity activity = getActivity(); boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations(); if (mViewModelStore != null && !isChangingConfigurations) { mViewModelStore.clear(); } }
當 Activity 或 Fragment 被系統重建時,ViewModel 物件不會被銷燬,新的 Activity 或 Fragment 物件拿到的是同一個 ViewModel 物件。
在 FragmentActivity#onRetainNonConfigurationInstance() 方法中,會將 ViewModelStore 物件保留起來。然後在 onCreate() 方法能獲取之前保留起來的 ViewModelStore 物件。
public final Object onRetainNonConfigurationInstance() { Object custom = onRetainCustomNonConfigurationInstance(); FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig(); if (fragments == null && mViewModelStore == null && custom == null) { return null; } NonConfigurationInstances nci = new NonConfigurationInstances(); nci.custom = custom; nci.viewModelStore = mViewModelStore; nci.fragments = fragments; return nci; } protected void onCreate(@Nullable Bundle savedInstanceState) { NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null && nc.viewModelStore != null && mViewModelStore == null) { mViewModelStore = nc.viewModelStore; } }
總結:
- 通過 ViewModelProviders 建立 ViewModelProvider 物件,呼叫ViewModelProvider的 get() 方法獲取 ViewModel 物件。 當 ViewModelStore 裡不存在想要的物件,ViewModelProvider 會使用 Factory 新建一個物件並存放到 ViewModelStore 裡。
- 當發生 發生 Configuration Changes 時,FragmentActivity 利用 getLastNonConfigurationInstance()、onRetainNonConfigurationInstance() 方法實現 ViewModelStore 的保留與恢復,進而實現 ViewModel 物件的保活。
- 當 FragmentActivity 和 Fragment 被銷燬時,會根據是否發生 Configuration Changes 來決定是否銷燬 ViewModel
參考文獻:
1、 ofollow,noindex">原始碼解析Android架構元件ViewModel