1. 從 ViewModelProvider(this).get(xxViewModel.class) 講起
首先,我們看看 ViewModelProvider 的構(gòu)造函數(shù):
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
上面代碼我們有兩個地方需要搞清楚,ViewModelStore 和 ViewModelProvider.NewInstanceFactory。大體上我們可以猜測到,前者是存儲 ViewModel 實(shí)例的,后者是構(gòu)造 ViewModel 實(shí)例的工廠。
1.1 ViewModelStore(存儲 ViewModel 的實(shí)例)
ViewModelProvider 的構(gòu)造函數(shù)接收一個 ViewModelStoreOwner,而 ViewModelStoreOwner 接口只有一個 getViewModelStore 方法,它返回一個 ViewModelStore。所以我們看看 ViewModelStore(顧名思義可以猜到它就是用來存儲 ViewModel 實(shí)例的):
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();
}
}
實(shí)現(xiàn)非常簡單:只有一個用于存儲 ViewModel 的 hash 表:
-
key 是由
ViewModelProvider生成的:DEFAULT_KEY + ":" + canonicalName,其中DEFAULT_KEY = androidx.lifecycle.ViewModelProvider.DefaultKey。 -
value 是
ViewModel的實(shí)例。
有點(diǎn)類似
ThreadLocal的實(shí)現(xiàn)原理,本質(zhì)上是有一個Entry,它存儲了ThreadLocal與value的映射
因此,ViewModelStore 的職責(zé)是保存 ViewModel 的實(shí)例,而 ViewModelStore 的 owner 類,則必須保證在發(fā)生配置改變時(shí),發(fā)生重建后,依然返回同一個 ViewModelStore 實(shí)例(這樣,我們就可以返回同一個 ViewModel)。我們的 ComponentActivity 就是一個 ViewModelStoreOwner,我們在后面小節(jié)將會看看在重建后,它是如何返回同一個 ViewModelStore 實(shí)例的。
1.2 ViewModelProvider.Factory(構(gòu)造 ViewModel 實(shí)例的工廠方法)
ViewModelProvider 的帶兩個參數(shù)的構(gòu)造函數(shù)的第二個參數(shù)是一個 Factory:
/**
* Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
*/
public interface Factory {
/**
* Creates a new instance of the given {@code Class}.
* <p>
*
* @param modelClass a {@code Class} whose instance is requested
* @param <T> The type parameter for the ViewModel.
* @return a newly created ViewModel
*/
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
從注釋和接口代碼中我們可以看出,它是一個實(shí)例化 ViewModel 的工廠,只有一個產(chǎn)生 ViewModel 實(shí)例的 create 方法。從方法簽名中我們就可以看出,它接收 Class,通過反射之類的方法來構(gòu)造 ViewModel。通常我們默認(rèn)使用的是 ViewModelProvider.NewInstanceFactory:
/**
* Simple factory, which calls empty constructor on the give class.
*/
public static class NewInstanceFactory implements Factory {
private static NewInstanceFactory sInstance;
/**
* Retrieve a singleton instance of NewInstanceFactory.
*
* @return A valid {@link NewInstanceFactory}
*/
@NonNull
static NewInstanceFactory getInstance() {
if (sInstance == null) {
sInstance = new NewInstanceFactory();
}
return sInstance;
}
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
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);
}
}
}
可以看到,默認(rèn)的 NewInstanceFactory 只是簡單地反射調(diào)用 ViewModel 的無參構(gòu)造函數(shù)來實(shí)例化傳入的 ViewModel。
2. Activity 中 ViewModel 的創(chuàng)建和獲取
我們從常用的獲取 ViewModel 方法出發(fā):
ChronometerViewModel chronometerViewModel
= new ViewModelProvider(this).get(ChronometerViewModel.class);
??
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");
}
// 這里的 get 方法就生成了我們上面 ViewModelStore 中的 key 值了
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
??
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
// 從 ViewModelStore 中獲取 ViewModel 實(shí)例
ViewModel viewModel = mViewModelStore.get(key);
// 如果獲取到,且確實(shí)是我們想要獲取的 ViewModel 類型,則直接返回
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
// 如果沒有獲取到 ViewModel 實(shí)例,則調(diào)用 Factory 進(jìn)行創(chuàng)建
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
// 將創(chuàng)建出來的 ViewModel 存入 ViewModelStore
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
從上面可以看到,當(dāng)我們調(diào)用 new ViewModelProvider(this).get(xxViewModel.class); 來實(shí)例化并獲取 xxViewModel 實(shí)例時(shí),其實(shí)就是從 1.1 的 ViewModelStore 中去取,如果沒有就用 1.2 的 newInstanceFactory 新構(gòu)造一個,并放入 1.1 的 ViewModelStore 以方便以后獲取同一個實(shí)例。
所以,配置重建后,能夠獲取同一個 ViewModel 實(shí)例的關(guān)鍵在于能夠獲取到同一個 ViewModelStore 的實(shí)例。
3. Activity 中 ViewModel 的保存和恢復(fù)
上一節(jié)中我們說了,ViewModel 的保存和恢復(fù)是本質(zhì)上依賴于 ViewModelStore 的保存和恢復(fù)。而 ViewModelStore 的保存和恢復(fù)則是利用了 Activity.onRetainNonConfigurationInstance 機(jī)制。
3.1 ViewModelStore 的保存
我們來看支持 ViewModel 機(jī)制的 ComponentActivity.onRetainNonConfigurationInstance 中是如何保存 ViewModelStore 的:
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
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;
}
// 將 ViewModelStore 保存在 NonConfigurationInstances 中。保存了 ViewModelStore 也就保存了 ViewModel
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
從上面我們可以看到,ViewModelStore 的保存是依賴于 onRetainNonConfigurationInstance 的,在 onRetainNonConfigurationInstance 回調(diào)時(shí),構(gòu)建了新的 NonConfigurationInstance 實(shí)例,并將現(xiàn)在的 ViewModelStore 賦值給它的 nci.viewModelStore 屬性。
3.2 ViewModelStore 的恢復(fù)
ViewModelStore 和 ViewModel 的恢復(fù)其實(shí)就是當(dāng)我們使用 ViewModelProvider 來獲取 ViewModel 實(shí)例時(shí),內(nèi)部自己進(jìn)行恢復(fù)的。我們來看看 ViewModelProvider 的構(gòu)造方法:
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
上面?zhèn)魅?Activity 作為 ViewModelStoreOwner,當(dāng)調(diào)用它的 getViewModelStore 時(shí) ViewModelStore 也就被恢復(fù)了:
@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.");
}
if (mViewModelStore == null) {
// 這里獲得的 NonConfigurationInstance 就是之前通過 onRetainNonConfigurationInstance 保存的
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
我們通過方法 getLastNonConfigurationInstance 獲取到之前保存的 NonConfigurationInstances,從而取出其中的 ViewModelStore。
4. onRetainNonConfigurationInstance 機(jī)制
通過上面的分析,我們知道,保存恢復(fù) ViewModelStore 和 ViewModel 的關(guān)鍵在于 onRetainNonConfigurationInstance 和 getLastNonConfigurationInstance 機(jī)制是如何起作用的?
通過查找方法引用,我們可以看到 onRetainNonConfigurationInstance 方法其實(shí)是在 Activity.retainNonConfigurationInstances 方法中被調(diào)用的:
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
// We're already stopped but we've been asked to retain.
// Our fragments are taken care of but we need to mark the loaders for retention.
// In order to do this correctly we need to restart the loaders first before
// handing them off to the next activity.
mFragments.doLoaderStart();
mFragments.doLoaderStop(true);
ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
}
// 注意 Activity 中的 NonConfigurationInstances 類與 ComponentActivity 中的 NonConfigurationInstances 類不一樣
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity; // 這里將 onRetainNonConfigurationInstance 返回值保存了下來,其中就包含了 ViewModelStore
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
而 Activity.retainNonConfigurationInstances 方法是在 ActivityThread.performDestroyActivity 方法中被調(diào)用的。而 ComponentActivity 中的 mLastNonConfigurationInstances 則是在 ComponentActivity.attach 方法中,由 ActivityThread.performLaunchActivity 時(shí)主動調(diào)用傳入進(jìn)來的。
因此綜上所述,ViewModelStore 在 Activity.onDestroy() 銷毀時(shí),通過 onRetainNonConfigurationInstance 時(shí)的回調(diào)被保存在了 NonConfigurationInstances 實(shí)例中,該實(shí)例被 ActivityThread 持有。下次 Activity 重建時(shí),由 ActivityThread.performLaunchActivity 方法中調(diào)用 Activity.attach 方法,再將 NonConfigurationInstances 實(shí)例傳給重建后的 Activity。
5. Activity 中 ViewModel 的銷毀
通過上節(jié)我們知道 ViewModel 可以跨越 Activity 的生命周期和重建,那么 Activity 的 ViewModel 怎么知道需要在什么時(shí)候銷毀呢?
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
如上面代碼所示,ViewModel 正是借助了生命周期的回調(diào),在 ON_DESTROY 回調(diào)時(shí),通過 isChangingConfigurations 方法判斷該 Activity 是否正處于因配置改變而重建中,如果不是的話,則可以清除 ViewModel。
6. Fragment 中 ViewModel 的創(chuàng)建和獲取
由于 Fragment 同樣也是實(shí)現(xiàn)了 ViewModelStoreOwner 接口,因此同在 Activity 中創(chuàng)建和獲取 ViewModel 一樣,給 ViewModelProvider 的構(gòu)造函數(shù)傳入自己的實(shí)例即可:
mSeekBarViewModel = new ViewModelProvider(this).get(SeekBarViewModel.class);
如果
Fragment要和其宿主Activity共用一個ViewModel,則可以向ViewModelProvider的構(gòu)造函數(shù)傳入其宿主Activity即可:mSeekBarViewModel = new ViewModelProvider(requireActivity()).get(SeekBarViewModel.class);
由上面的 (2) 我們知道,創(chuàng)建和獲取 ViewModel 的關(guān)鍵在于 getViewModelStore 方法,而這個方法的實(shí)現(xiàn)上,Activity 和 Fragment 是不相同的:
-
Fragment的getViewModelStore是從FragmentManager.getViewModelStore中獲取的。 -
Activity的getViewModelStore是從ComponentActivity.getViewModelStore獲取的,它是直接存儲在mViewModelStore中的(根據(jù) (4),mViewModelStore是在Activityattach 時(shí),由ActivityThread傳入的)。
因此我們下面分析的重點(diǎn)應(yīng)該在于 FragmentManager.getViewModelStore 的機(jī)制。
6.1 FragmentActivity 在初始化時(shí)做了什么
Fragment 是依附于 FragmentActivity 的,因此對 FragmentManager 的操作一定也是通過 FragmentActivity 來完成的。
我們可以注意到在 FragmentActivity.onCreate 中調(diào)用了 mFragments.attachHost:
mFragments.attachHost(null /*parent*/);
最終調(diào)用到了 FragmentManager.attachController (注意,這里的 FragmentManager 就是根 Fragment 中的 mFragmentManager):
// 該方法在 FragmentManager 中。host 為 FragmentActivity.HostCallbacks。
void attachController(@NonNull FragmentHostCallback<?> host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
...
// Get the FragmentManagerViewModel
if (parent != null) { // FragmentActivity 中傳入的 parent 為 null,因此不會走這里
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) { // ??調(diào)用到這里
// 這里最終獲取的是 FragmentActivity 的 ViewModelStore
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
// mNonConfig 是這個 FragmentManager 對應(yīng)的 Fragment 的 ViewModel。
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
}
因?yàn)樵?FragmentActivity 中傳入的 parent 為 null,且 FragmentActivity.HostCallbacks 實(shí)現(xiàn)了 ViewModelStoreOwner,因此會走到上面的第二個條件分支。
而 FragmentActivity.HostCallbacks.getViewModelStore 就是調(diào)用的 FragmentActivity.getViewModelSotre(是的,HostCallbacks 就是繞了一下而已),因此上面代碼創(chuàng)建的實(shí)例 mNonConfig: FragmentManagerViewModel,其實(shí)存入到了兩個地方:
1. FragmentActivity 的 ViewModelStore 中,所以 FragmentActivity.mViewModelStore 中不僅有 Activity 環(huán)境下創(chuàng)建的 ViewModel ,還包含了一個(或多個)根 Fragment 對應(yīng)的 FragmentManagerViewModel。
2. FragmentManager.mNonConfig(注意 mNonConfig 是一個 FragmentManagerViewModel 的實(shí)例) 中
這兩點(diǎn)很重要。
6.2 在根 Fragment 中獲取 ViewModel
我們知道關(guān)鍵點(diǎn)在于調(diào)用的 Fragment.getViewModelStore:
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
// 這里的 mFragmentManager 實(shí)例就是 FragmentActivity.HostCallbacks 內(nèi)部類中的 mFragmentManager,
// 也就是在 (6.1) 節(jié)中我們提到擁有 FragmentManagerViewModel 的那個 FragmentManager
return mFragmentManager.getViewModelStore(this);
}
// FragmentManager ??
ViewModelStore getViewModelStore(@NonNull Fragment f) {
// 這里的 mNonConfig 根據(jù) (6.1) 節(jié),是一個 FragmentManagerViewModel 的實(shí)例
return mNonConfig.getViewModelStore(f);
}
從上面代碼和注釋中我們可以知道
- 根
Fragment的getViewModelStore最終是從FragmentManagerViewModel.getViewModelStore中獲取的。這與FragmentActivity: ComponentActivity的getViewModelStore來源不一樣,因此在FragmentActivity和Fragment中都獲取同樣類型(類名一樣)的ViewModel,獲取出來的實(shí)例卻是不一樣的。 - 根據(jù) (6.1) 我們可以知道,根
Fragment.getViewModelStore的最終調(diào)用處FragmentManagerViewModel.getViewModelStore中的FragmentManagerViewModel實(shí)例,其實(shí)在FragmentActivity.onCreate時(shí)就已經(jīng)存入了FragmentActivity的ViewModelStore中。也就是說它們之間的結(jié)構(gòu)是下面這樣的:
FragmentManagerViewModel 與 Activity 的關(guān)系
所以,Activity 中創(chuàng)建的 ViewModel 是來自于它的 mViewModelStore。而根 Fragment 中創(chuàng)建的 ViewModel 是來自于它的宿主 Activity 的 mViewModelStore.FragmentManagerViewModel.mViewModelStores。
這里
mViewModelStores是復(fù)數(shù)的原因是,一個Activity可能有多個根Fragment。
6.3 Fragment 創(chuàng)建時(shí)做了什么
從 (6.2) 最后的結(jié)論我們知道,FragmentActivity 在 onCreate 時(shí)就做好了如下引用鏈:activity: FragmentActivity → mViewModelStore: ViewModelStore → 里面有一個 key 對應(yīng)的是 FragmentManagerViewModel → FragmentManagerViewModel.mViewModelStores。
Q: 那么 根Fragment 是否也對 子Fragment 做了同樣的準(zhǔn)備?
各個層級的 Fragment 與它對應(yīng)的 FragmentManager 有如下對應(yīng)關(guān)系:
-
根Fragment→FragmentActivity.FragmentController.mHost.mFragmentManager以及它自己的mFragmentManager: FragmentManagerImpl。 -
子Fragment→父Fragment.getChildFragmentManager以及 它自己的mFragmentManager: FragmentManagerImpl。
當(dāng) 根Fragment 關(guān)聯(lián)到 Activity 上時(shí),會調(diào)用其 performAttach 方法:
// androidx.fragment.app.Fragment
void performAttach() {
// 類比于 FragmentActivity.onCreate 中的 mFragments.attachHost -> mHost.mFragmentManager.attachController
mChildFragmentManager.attachController(mHost, new FragmentContainer() {
@Override
@Nullable
public View onFindViewById(int id) {
if (mView == null) {
throw new IllegalStateException("Fragment " + this + " does not have a view");
}
return mView.findViewById(id);
}
@Override
public boolean onHasView() {
return (mView != null);
}
}, this);
mState = ATTACHED;
mCalled = false;
onAttach(mHost.getContext());
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onAttach()");
}
}
之后,它們通過各自的 FragmentManager 操作,在各層級的 FragmentManagerViewModel 之間建立了如下圖的關(guān)系。

所以,各層級的
Fragment 的 ViewModel 能夠恢復(fù),也是受益于 Activity 中 ViewModelStore 的恢復(fù)。
番外:理解 FragmentHostCallback 和 FragmentController
從上面的代碼中,我們可以注意到在 FragmentActivity 中有一個內(nèi)部類 HostCallbacks,這個類繼承自 FragmentHostCallback,但是它的所有實(shí)現(xiàn)方法都只是調(diào)用它的外部類 FragmentActivity 的相應(yīng)方法而已,它自己沒有任何實(shí)質(zhì)的操作。
從 FragmentHostCallback 的類注釋中我們可以知道,該類主要是為了面向 Fragment 宿主提供一個統(tǒng)一的 Fragment 相關(guān)信息的回調(diào),包括 onGetLayoutInflater,onShouldSaveFragmentState 等。這些回調(diào)有的來自 Fragment 類,有的來自 FragmentManager 類,因此 FragmentHostCallback 是 Fragment 向外暴露信息的回調(diào)的整合點(diǎn)。目前 FragmentHostCallback 的唯一實(shí)現(xiàn)類是 FragmentActivity 的內(nèi)部類 HostCallbacks。內(nèi)部類可以直接調(diào)用它的外部類,這樣,Fragment 的相關(guān)信息回調(diào)就通過 FragmentActivity.HostCallbacks 傳給了 FragmentActivity。
FragmentHostCallback 類不僅向宿主類提供 Fragment 的相關(guān)事件回調(diào),它還持有一個 FragmentManager 的實(shí)例 mFragmentManager,并且該實(shí)例在 FragmentHostCallback 中沒有任何使用。我們查看 mFragmentManager 使用的地方可以發(fā)現(xiàn)都是在 FragmentController 中。
FragmentController 通過構(gòu)造函數(shù)傳入 FragmentHostCallback 的實(shí)例 mHost,再通過 mHost 調(diào)用到 mFragmentManager。我們看看 FragmentController 的方法,可以發(fā)現(xiàn)幾乎都是宿主 FragmentActivity 主動調(diào)用的 生命周期方法 以及 需要從 Fragment 中獲取數(shù)據(jù)的方法,例如獲取 FragmentManager 實(shí)例。

