ViewModel
是 Android 架構(gòu)組件之一栓辜,用于分離 UI 邏輯與 UI 數(shù)據(jù)恋拍。在發(fā)生 Configuration Changes 時(shí),它不會(huì)被銷毀藕甩。在界面重建后施敢,方便開發(fā)者呈現(xiàn)界面銷毀前的 UI 狀態(tài)。
本文主要分析 ViewModel
的以下3個(gè)方面:
- 獲取和創(chuàng)建過程狭莱。
- Configuration Changes 存活原理僵娃。
- 銷毀過程。
1. 依賴庫
implementation "androidx.fragment:fragment:1.0.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:2.0.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
2. 主要類與接口
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProvider.Factory;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelStore;
import androidx.lifecycle.ViewModelStoreOwner;
3. ViewModel
ViewModel
是一個(gè)抽象類贩毕,類中只定義了一個(gè)空實(shí)現(xiàn)的 onCleared()
方法悯许。
public abstract class ViewModel {
/**
* This method will be called when this ViewModel is no longer used and will be destroyed.
* <p>
* It is useful when ViewModel observes some data and you need to clear this subscription to
* prevent a leak of this ViewModel.
*/
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
}
3.1 AndroidViewModel
AndroidViewModel
類擴(kuò)展了 ViewModel
類,增加了 Application
字段辉阶,在構(gòu)造方法初始化先壕,并提供了 getApplication()
方法。
public class AndroidViewModel extends ViewModel {
private Application mApplication;
public AndroidViewModel(@NonNull Application application) {
mApplication = application;
}
/**
* Return the application.
*/
@NonNull
public <T extends Application> T getApplication() {
return (T) mApplication;
}
}
4. 獲取和創(chuàng)建過程分析
獲取 ViewModel
對象代碼如下:
ViewModelProviders.of(activityOrFragment).get(ViewModel::class.java)
4.1 ViewModelProviders
ViewModelProviders
類提供了4個(gè)靜態(tài)工廠方法 of()
創(chuàng)建新的 ViewModelProvider
對象谆甜。
ViewModelProviders.of(Fragment)
ViewModelProviders.of(FragmentActivity)
ViewModelProviders.of(Fragment, Factory)
ViewModelProviders.of(FragmentActivity, Factory)
4.2 ViewModelProvider
ViewModelProvider
負(fù)責(zé)提供 ViewModel
對象垃僚,類中定義了以下兩個(gè)字段:
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
先說說這兩個(gè)類的功能。
4.3 ViewModelProvider.Factory
Factory
接口定義了一個(gè)創(chuàng)建 ViewModel
的接口 create()
规辱,ViewModelProvider
在需要時(shí)調(diào)用該方法新建 ViewModel
對象谆棺。
public interface Factory {
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
Android 已經(jīng)內(nèi)置了2個(gè) Factory
實(shí)現(xiàn)類,分別是:
-
AndroidViewModelFactory
實(shí)現(xiàn)類罕袋,可以創(chuàng)建ViewModel
和AndroidViewModel
子類對象改淑。 -
NewInstanceFactory
類,只可以創(chuàng)建ViewModel
子類對象浴讯。
它們的實(shí)現(xiàn)都是通過反射機(jī)制調(diào)用 ViewModel
子類的構(gòu)造方法創(chuàng)建對象朵夏。
public static class NewInstanceFactory implements Factory {
@Override
public <T extends ViewModel> T create(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);
}
}
}
AndroidViewModelFactory
繼承 NewInstanceFactory
類,是個(gè)單例榆纽,支持創(chuàng)建 AndroidViewModel
子類對象仰猖。
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
public static AndroidViewModelFactory getInstance(Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
public AndroidViewModelFactory(Application application) {
mApplication = application;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
try {
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);
}
}
return super.create(modelClass);
}
}
4.4 ViewModelStore
ViewModelStore
類中維護(hù)一個(gè) Map<String, ViewModel>
對象存儲(chǔ)已創(chuàng)建的 ViewModel
對象,并提供 put()
和 get()
方法奈籽。
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
}
final ViewModel get(String key) {
return mMap.get(key);
}
}
4.5 ViewModelStoreOwner
ViewModelStore
是來自于 FragmentActivity
和 Fragment
饥侵,它們實(shí)現(xiàn)了 ViewModelStoreOwner
接口,返回當(dāng)前 UI 作用域里的 ViewModelStore
對象衣屏。
public interface ViewModelStoreOwner {
ViewModelStore getViewModelStore();
}
在 Fragment
類中的實(shí)現(xiàn)如下:
public ViewModelStore getViewModelStore() {
if (getContext() == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}
在 FragmentActivity
類中的實(shí)現(xiàn)如下:
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) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}
4.6 創(chuàng)建 ViewModelProvider
回到 of()
方法的實(shí)現(xiàn)躏升。
public static ViewModelProvider of(FragmentActivity activity, Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
在創(chuàng)建 ViewModelProvider
對象時(shí)需要傳入 ViewModelStore
和 Factory
對象。若 factory
為 null
狼忱,將使用 AndroidViewModelFactory
單例對象煮甥。
4.7 獲取 ViewModel
對象
調(diào)用 ViewModelProvider
對象的 get()
方法獲取 ViewModel
對象盗温,如果在 ViewModelStore
里不存在藕赞,則使用 Factory
創(chuàng)建一個(gè)新的對象并存放到 ViewModelStore
里成肘。
public <T extends ViewModel> T get(String key, Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
5. Configuration Changes 存活原理
當(dāng) Activity
或 Fragment
被系統(tǒng)重建時(shí),ViewModel
對象不會(huì)被銷毀斧蜕,新的 Activity
或 Fragment
對象拿到的是同一個(gè) ViewModel
對象双霍。
在 FragmentActivity#onRetainNonConfigurationInstance()
方法中,會(huì)將 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;
}
然后在 onCreate()
方法能獲取之前保留起來的 ViewModelStore
對象洒闸。
protected void onCreate(Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
// ...
}
那 Fragment
作用域里是如何實(shí)現(xiàn)的呢?在 FragmentActivity
的 onRetainNonConfigurationInstance()
方法中里有這樣一句代碼:
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
實(shí)現(xiàn)保留的機(jī)制是一樣的均芽,只不過放在 FragmentManagerNonConfig
對象中丘逸。是在 FragmentManager#saveNonConfig()
方法中將 ViewModelStore
對象保存到 FragmentManagerNonConfig
里的。
void saveNonConfig() {
ArrayList<Fragment> fragments = null;
ArrayList<FragmentManagerNonConfig> childFragments = null;
ArrayList<ViewModelStore> viewModelStores = null;
if (mActive != null) {
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.valueAt(i);
if (f != null) {
if (f.mRetainInstance) {
if (fragments == null) {
fragments = new ArrayList<Fragment>();
}
fragments.add(f);
f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
}
FragmentManagerNonConfig child;
if (f.mChildFragmentManager != null) {
f.mChildFragmentManager.saveNonConfig();
child = f.mChildFragmentManager.mSavedNonConfig;
} else {
// f.mChildNonConfig may be not null, when the parent fragment is
// in the backstack.
child = f.mChildNonConfig;
}
if (childFragments == null && child != null) {
childFragments = new ArrayList<>(mActive.size());
for (int j = 0; j < i; j++) {
childFragments.add(null);
}
}
if (childFragments != null) {
childFragments.add(child);
}
if (viewModelStores == null && f.mViewModelStore != null) {
viewModelStores = new ArrayList<>(mActive.size());
for (int j = 0; j < i; j++) {
viewModelStores.add(null);
}
}
if (viewModelStores != null) {
viewModelStores.add(f.mViewModelStore);
}
}
}
}
if (fragments == null && childFragments == null && viewModelStores == null) {
mSavedNonConfig = null;
} else {
mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments,
viewModelStores);
}
}
該方法的調(diào)用順序是:FragmentActivity#onSaveInstanceState()
-> FragmentManager#saveAllState()
-> FragmentManager#saveNonConfig()
掀宋。
6. 銷毀過程
在 FragmentActivity
類的 onDestory()
方法中深纲。
@Override
protected void onDestroy() {
super.onDestroy();
if (mViewModelStore != null && !isChangingConfigurations()) {
mViewModelStore.clear();
}
mFragments.dispatchDestroy();
}
在 Fragment
類的 onDestory()
方法中。
public void onDestroy() {
mCalled = true;
FragmentActivity activity = getActivity();
boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations();
if (mViewModelStore != null && !isChangingConfigurations) {
mViewModelStore.clear();
}
}
先判斷是否有發(fā)生 Configuration Changes劲妙,如果沒有則會(huì)調(diào)用 ViewModelStore
的 clear()
方法湃鹊,再一一調(diào)用每一個(gè) ViewModel
的 onCleared()
方法。
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
7. 總結(jié)
以上便是 ViewModel
3個(gè)主要過程的剖析镣奋,這里做一下總結(jié)币呵。
- 通過
ViewModelProviders
創(chuàng)建ViewModelProvider
對象,調(diào)用該對象的get()
方法獲取ViewModel
對象侨颈。 當(dāng)ViewModelStore
里不存在想要的對象余赢,ViewModelProvider
會(huì)使用Factory
新建一個(gè)對象并存放到ViewModelStore
里。 - 當(dāng)發(fā)生 發(fā)生 Configuration Changes 時(shí)哈垢,
FragmentActivity
利用getLastNonConfigurationInstance()
妻柒、onRetainNonConfigurationInstance()
方法實(shí)現(xiàn)ViewModelStore
的保留與恢復(fù),進(jìn)而實(shí)現(xiàn)ViewModel
對象的蔽屡猓活蛤奢。 - 當(dāng)
FragmentActivity
和Fragment
被銷毀時(shí),會(huì)根據(jù)是否發(fā)生 Configuration Changes 來決定是否銷毀ViewModel
陶贼。