Android 架構元件 ViewModel:原始碼分析
本篇主要關注ViewModel
的實現而非其用法,關於它的用法,可以參考這裡[2]
。
ViewModel
主要用於在 activity/fragment 被自動銷燬時儲存一些資料。從實現原理上講,主要就是利用了fragment.setRetainInstance(true)。如此一來,這個fragment
就能夠跨越activity
的生命週期。
以下原始碼使用 1.1.1 版本
總覽
-
ViewModel
這個是我們的主角,我們定義的 model 類需要繼承它
-
ViewModelProvider
用於生成 ViewModel 例項
-
ViewModelStore
跟他的名字一樣,主要用來儲存 ViewModel 的例項
-
HolderFragment
ViewModelStore 例項儲存會在這裡
下面是 Google 給出的示例[3] step2 中的一段程式碼:
ChronometerViewModel chronometerViewModel= ViewModelProviders.of(this).get(ChronometerViewModel.class);
下面我們就根據這個呼叫來學習ViewModel
的原始碼。
ViewModel
前面我們說過,自己定義的 model 類需要繼承它。這裡借花獻佛,我們直接看 Google 的 sample:
public class ChronometerViewModel extends ViewModel {// 不用關心它的內容}
ViewModel
雖然是主角,但他非常的簡單:
public abstract class ViewModel {protected void onCleared() {}}
就這樣,他只是定義了一個空方法onCleared()
。當對應的 model 例項被銷燬時,onCleared()
將會執行。通過讓他成為abstract class
並給予onCleared
一個預設實現,讓ViewModel
有了 tag interface 的效果。
所謂的 tag interface 是指不帶任何方法的interface
。
接下來是男二號AndroidViewModel
:
public class AndroidViewModel extends ViewModel {private Application mApplication;public AndroidViewModel(@NonNull Application application) {mApplication = application;}@NonNullpublic <T extends Application> T getApplication() {return (T) mApplication;}}
沒有太多可圈可點的東西,我們繼續看下一個。
ViewModelProvider
ChronometerViewModel chronometerViewModel= ViewModelProviders.of(this).get(ChronometerViewModel.class);
我們繼續從這個呼叫往下看。
ViewModelProviders
可以看成是ViewModelProvider
的工廠或相關工具類的合集。他的命名跟 JDK 裡的 Collections/Arrays 類似。這裡的this
是 FragmentActivity,所以接下來執行的是:
public class ViewModelProviders {@NonNull@MainThreadpublic static ViewModelProvider of(@NonNull FragmentActivity activity) {return of(activity, null);}@NonNull@MainThreadpublic static ViewModelProvider of(@NonNull FragmentActivity activity,@Nullable Factory factory) {Application application = checkApplication(activity);if (factory == null) {factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);}return new ViewModelProvider(ViewModelStores.of(activity), factory);}}
可以看到,最終ViewModelProviders
會建立一個ViewModelProvider
例項並返回。
Factory
是用於建立 model 例項的工廠:
public interface Factory {@NonNull<T extends ViewModel> T create(@NonNull Class<T> modelClass);}
預設的實現是AndroidViewModelFactory
:
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {private static AndroidViewModelFactory sInstance;@NonNullpublic static AndroidViewModelFactory getInstance(@NonNull Application application) {if (sInstance == null) {sInstance = new AndroidViewModelFactory(application);}return sInstance;}@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {if (AndroidViewModel.class.isAssignableFrom(modelClass)) {// model 類繼承了 AndroidViewModel//noinspection TryWithIdenticalCatchestry {return modelClass.getConstructor(Application.class).newInstance(mApplication);} catch (NoSuchMethodException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (IllegalAccessException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (InstantiationException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (InvocationTargetException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);}}// 否則,由父類 `NewInstanceFactory` 處理return super.create(modelClass);}}
父類NewInstanceFactory
的實現一樣很簡單:
public static class NewInstanceFactory implements Factory {@SuppressWarnings("ClassNewInstance")@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {try {return modelClass.newInstance();} catch (InstantiationException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (IllegalAccessException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);}}}
從這裡可以看出,使用預設的Factory
實現時,如果 model 類繼承ViewModel
,需要有一個預設建構函式;如果繼承AndroidViewModel
,必須有一個以Application
為唯一引數建構函式。否則,我們需要自己實現一個Factory
。
我們先把ViewModelStore
放一放,先假設成功拿到了他的例項,於是,我們建立ViewModelProvider
例項:
public static ViewModelProvider of(@NonNull FragmentActivity activity,@Nullable Factory factory) {// ...return new ViewModelProvider(ViewModelStores.of(activity), factory);}public class ViewModelProvider {public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {mFactory = factory;mViewModelStore = store;}// ...}
通過ViewModelProvider
獲取 model 例項時,使用的是他的get
方法:
public class ViewModelProvider {private static final String DEFAULT_KEY ="android.arch.lifecycle.ViewModelProvider.DefaultKey";@NonNull@MainThreadpublic <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);}@NonNull@MainThreadpublic <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {ViewModel viewModel = mViewModelStore.get(key);// 當使用不同的類載入器載入同一個類的時候,這裡會是 falseif (modelClass.isInstance(viewModel)) {//noinspection uncheckedreturn (T) viewModel;} else {//noinspection StatementWithEmptyBodyif (viewModel != null) {// TODO: log a warning.}}viewModel = mFactory.create(modelClass);mViewModelStore.put(key, viewModel);//noinspection uncheckedreturn (T) viewModel;}}
ViewModelProvider
他的職責就是從ViewModelStore
裡取出物件,如果物件不存在,就新建立一個,並把新建立的這個物件放到ViewModelStore
。
ViewModelStore
和 ViewModelProvider 一樣,ViewModelStore 也有一個工廠類叫 ViewModelStores。
public class ViewModelStores {@NonNull@MainThreadpublic static ViewModelStore of(@NonNull FragmentActivity activity) {// 我們的 activity 可以自己實現 ViewModelStoreOwner// 預設情況下,這裡的判斷為 false,ViewModelStoreOwner 由 HolderFragment 實現if (activity instanceof ViewModelStoreOwner) {return ((ViewModelStoreOwner) activity).getViewModelStore();}// holderFragmentFor 在 HolderFragment 中實現,我們留到下一節再看return holderFragmentFor(activity).getViewModelStore();}}public interface ViewModelStoreOwner {@NonNullViewModelStore getViewModelStore();}
HolderFragment 實現了 ViewModelStoreOwner 介面,holderFragmentFor(activity) 返回 activity 對應的 holderFragment 後,即可以拿到 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);}/***Clears internal storage and notifies ViewModels that they are no longer used.*/public final void clear() {for (ViewModel vm : mMap.values()) {vm.onCleared();}mMap.clear();}}
HolderFragment
HolderFragment
是整個實現的核心。
public class HolderFragment extends Fragment implements ViewModelStoreOwner {// ...public HolderFragment() {// 如此一來,當 activity 由於螢幕旋轉等被系統銷燬時,這個 fragment 例項也不會被銷燬setRetainInstance(true);}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 把 activity 從 mNotCommittedActivityHolders 中移除sHolderFragmentManager.holderFragmentCreated(this);}public static HolderFragment holderFragmentFor(FragmentActivity activity) {return sHolderFragmentManager.holderFragmentFor(activity);}static class HolderFragmentManager {private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();private ActivityLifecycleCallbacks mActivityCallbacks =new EmptyActivityLifecycleCallbacks() {@Overridepublic void onActivityDestroyed(Activity activity) {HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);// fragment 建立成功後,會把 activity 從 mNotCommittedActivityHolders 中// 移除。如果 fragment != null,說明 fragment 沒有建立完 activity 就跪了if (fragment != null) {Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);}}};private boolean mActivityCallbacksIsAdded = false;HolderFragment holderFragmentFor(FragmentActivity activity) {FragmentManager fm = activity.getSupportFragmentManager();// 通過 fragmentManager 獲取 fragment 例項HolderFragment holder = findHolderFragment(fm);if (holder != null) {return holder;}holder = mNotCommittedActivityHolders.get(activity);if (holder != null) {return holder;}if (!mActivityCallbacksIsAdded) {mActivityCallbacksIsAdded = true;activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);}holder = createHolderFragment(fm);// 我們 add 進去的 fragment 並不會馬上就執行完(也就是說,這個方法執行完成後,馬上再// 呼叫一次,上面的 findHolderFragment 會返回 null。但是這沒有關係,因為接下來我們還可// 從 mNotCommittedActivityHolders 獲取到對應的例項),所以我們這裡先把他放在// mNotCommittedActivityHolders 中。Not Committed 表示 fragment 的 commit 還沒有完成mNotCommittedActivityHolders.put(activity, holder);return holder;}private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {HolderFragment holder = new HolderFragment();// 這個 fragment 只是用來存資料,允許他的狀態丟失可以讓使用者在更多情景下使用我們的API// 例如,onStop() 中也可以使用(當然,onDestroy 就不行了,因為我們需要往 activity 悄悄// 新增一個 fragment)fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();return holder;}}}
HolderFragment
對 ViewModelStoreOwner 實現是相當直接的:
public class HolderFragment extends Fragment implements ViewModelStoreOwner {private ViewModelStore mViewModelStore = new ViewModelStore();@Overridepublic void onDestroy() {super.onDestroy();mViewModelStore.clear();}@NonNull@Overridepublic ViewModelStore getViewModelStore() {return mViewModelStore;}}
到這裡,ViewModel
的實現我們就看完了。需要注意的是,ViewModel
還支援fragment
,這部分跟activity
是類似的,有興趣的讀者自己看一看就好。