
Q:ViewModel是什么?
ViewModel是MVVM架構(gòu)的一個(gè)層級(jí),用來(lái)聯(lián)系View和model之間的關(guān)系。
官方文檔解釋:
ViewModel 類旨在以注重生命周期的方式存儲(chǔ)和管理界面相關(guān)的數(shù)據(jù)。
- 注重生命周期的方式
由于ViewModel的生命周期是作用于整個(gè)Activity的,所以就節(jié)省了一些關(guān)于狀態(tài)維護(hù)的工作,最明顯的就是對(duì)于屏幕旋轉(zhuǎn)這種情況,以前對(duì)數(shù)據(jù)進(jìn)行保存讀取,而ViewModel則不需要,他可以自動(dòng)保留數(shù)據(jù)。
其次,由于ViewModel在生命周期內(nèi)會(huì)保持局部單例,所以可以更方便Activity的多個(gè)Fragment之間通信,因?yàn)樗麄兡塬@取到同一個(gè)ViewModel實(shí)例,也就是數(shù)據(jù)狀態(tài)可以共享了。
- 存儲(chǔ)和管理界面相關(guān)的數(shù)據(jù)
ViewModel層的根本職責(zé),就是負(fù)責(zé)維護(hù)界面上UI的狀態(tài),其實(shí)就是維護(hù)對(duì)應(yīng)的數(shù)據(jù),因?yàn)閿?shù)據(jù)會(huì)最終體現(xiàn)到UI界面上。所以ViewModel層其實(shí)就是對(duì)界面相關(guān)的數(shù)據(jù)進(jìn)行管理,存儲(chǔ)等操作。
Q:請(qǐng)談?wù)勈褂肰iewModel的好處?
ViewModel類旨在以注重生命周期的形式存儲(chǔ)和管理界面相關(guān)的數(shù)據(jù)。
1.ViewModel類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存。
2.界面控制器經(jīng)常需要進(jìn)行需要一些時(shí)間才會(huì)返回的異步調(diào)用 ,界面控制器需要管理這些調(diào)用,并確保系統(tǒng)在其銷毀后清理這些調(diào)用以避免潛在的內(nèi)存泄漏。此項(xiàng)管理需要大量的維護(hù)工作,并且在為配置更改重新創(chuàng)建對(duì)象的情況下,會(huì)造成資源的浪費(fèi),因?yàn)閷?duì)象可能需要重新發(fā)出已經(jīng)發(fā)出過(guò)的調(diào)用。
3.諸如 Activity 和 Fragment 之類的界面控制器主要用于顯示界面數(shù)據(jù)、對(duì)用戶操作做出響應(yīng)或處理操作系統(tǒng)通信(如權(quán)限請(qǐng)求)。如果要求界面控制器也負(fù)責(zé)從數(shù)據(jù)庫(kù)或網(wǎng)絡(luò)加載數(shù)據(jù),那么會(huì)使類越發(fā)膨脹。為界面控制器分配過(guò)多的責(zé)任可能會(huì)導(dǎo)致單個(gè)類嘗試自己處理應(yīng)用的所有工作,而不是將工作委托給其他類。以這種方式為界面控制器分配過(guò)多的責(zé)任也會(huì)大大增加測(cè)試的難度。
從界面控制器邏輯中分離出視圖數(shù)據(jù)所有權(quán)的操作更容易且更高效。
Q:為什么不能在ViewModel中引用view、Lifecycle或任何可能持有Activity Context的類?
ViewModels存在的時(shí)間比View或LifecycleOwners的特定實(shí)例存在的時(shí)間更長(zhǎng)——如果您將Activity旋轉(zhuǎn)3次,則您剛剛創(chuàng)建了三個(gè)不同的Activity實(shí)例,但是只有一個(gè)ViewModel實(shí)例。
如果 ViewModel 需要 Application 上下文(例如,為了查找系統(tǒng)服務(wù)),它可以擴(kuò)展 AndroidViewModel 類并設(shè)置用于接收 Application 的構(gòu)造函數(shù),因?yàn)?Application類會(huì)擴(kuò)展 Context。
Q:ViewModel是否對(duì)數(shù)據(jù)使用了持久化?
ViewModel 持有 UI 中的臨時(shí)數(shù)據(jù),但是他們不會(huì)進(jìn)行持久化。一旦相關(guān)聯(lián)的 UI 控制器(fragment/activity)被銷毀或者進(jìn)程停止了,ViewModel 和所有被包含的數(shù)據(jù)都將被垃圾回收機(jī)制標(biāo)記。
Q:onSaveInstanceState()和ViewModel的區(qū)別?
onSaveInstanceState() ->這個(gè)回調(diào)是為了保存兩種情況下的少量 UI 相關(guān)的數(shù)據(jù):
- 應(yīng)用進(jìn)程在后臺(tái)時(shí)由于內(nèi)存限制而被終止
- 配置更改
onSaveInstanceState()是被系統(tǒng)在 activity stopped但沒(méi)有 finished 時(shí)調(diào)用的,而不是在用戶顯式地關(guān)閉 activity 或者在其他情形而導(dǎo)致finish()被調(diào)用的時(shí)候調(diào)用。
onSaveInstanceState()不是被設(shè)計(jì)來(lái)存儲(chǔ)類似 bitmap 這樣的大的數(shù)據(jù)的。onSaveInstanceState()方法被設(shè)計(jì)用來(lái)存儲(chǔ)那些小的與 UI 相關(guān)的并且序列化或者反序列化不復(fù)雜的數(shù)據(jù)。如果被序列化的對(duì)象是復(fù)雜的話,序列化會(huì)消耗大量的內(nèi)存。由于這一過(guò)程發(fā)生在主線程的配置更改期間,它需要快速處理才不會(huì)丟幀和引起視覺(jué)上的卡頓。
onRetainNonConfigurationInstance()->onSaveInstanceState方法保存數(shù)據(jù)到Bundle,Bundle是有類型限制和大小限制的,而且也要在主線程序列化和反序列化數(shù)據(jù),而onRetainNonConfigurationInstance是保存數(shù)據(jù)到Object,類型和大小都沒(méi)有限制。
Fragment.setRetainInstance(true)->創(chuàng)建一個(gè)保留 fragment 的好處是這可以保存類似 image 那樣的大型數(shù)據(jù)集或者網(wǎng)絡(luò)連接那樣的復(fù)雜對(duì)象。
ViewModel->只能在配置更改相關(guān)的銷毀的情況下保留,而不能在被終止的進(jìn)程中存留。這使 ViewModel 成為搭配
setRetainInstance(true)(實(shí)際上,ViewModel 在幕后使用了一個(gè) fragment 并將 setRetainInstance 方法中的參數(shù)設(shè)置為 true) 一塊使用的 fragment 的一種替代品。

Q:ViewModel實(shí)現(xiàn)機(jī)制包含了什么設(shè)計(jì)模式?
工廠模式:ViewModelProviders 實(shí)際相當(dāng)于一個(gè) 簡(jiǎn)單工廠 模式,根據(jù)不同的參數(shù)構(gòu)造不同的 ViewModelProvider;而 Facotry 則是一個(gè) 工廠方法 模式可以實(shí)現(xiàn)不同的具體 Factory 來(lái)構(gòu)造不同的 ViewModel。
val ViewModel1 = ViewModelProviders.of(activity,factory).get(ViewModel::class.java)
val ViewModel2 = ViewModelProviders.of(fragment,factory).get(ViewModel::class.java)
Q:ViewModel是如何創(chuàng)建的,又是什么時(shí)候被銷毀?
1. 根據(jù)Activity或Fragment使用ViewModelProviders.of方法獲得ViewModelProvider實(shí)例
創(chuàng)建ViewModelProvider實(shí)例需要兩個(gè)參數(shù)ViewModelStoreOwner以及Factory
- Factory -> 定義了創(chuàng)建ViewModel的行為接口。里面只有一個(gè)create方法,用于子類自行決定如何實(shí)現(xiàn)一個(gè)ViewModel對(duì)象的創(chuàng)建。
public interface Factory {
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
- ViewModelStoreOwer -> ViewModelStore的持有者,提供了獲取ViewModelStore實(shí)例的方法,ViewModelStore就是個(gè)HashMap,通過(guò)key來(lái)獲取ViewModel對(duì)象。
public interface ViewModelStoreOwner {
ViewModelStore getViewModelStore();
}
2. 使用ViewModelProvider.get()創(chuàng)建需要的ViewModel
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
- 使用ViewModel Class的canonicalName作為ViewModel在ViewModelStore中的唯一標(biāo)識(shí)。
- 通過(guò)唯一標(biāo)識(shí),先查詢一下ViewModelStore中是否有該ViewModel對(duì)象,如果有則直接返回。
- 如果ViewModelStore中沒(méi)有該ViewModel對(duì)象,則通過(guò)Factory工廠類
mFactory.create反射創(chuàng)建出ViewModel對(duì)象,存入ViewModelStore中,并返回給調(diào)用者。這里如果沒(méi)有傳入Factory則會(huì)判斷ViewModel類型是否是AndroidViewModel,如果是,則使用默認(rèn)的AndroidViewModelFactory,如果不是則使用AndroidViewModelFactory的父類NewInstanceFactory,即調(diào)用Class的無(wú)參構(gòu)造函數(shù)創(chuàng)建ViewModel對(duì)象
Q: ViewModel的銷毀
- Activity中的銷毀
在ComponentActivity的構(gòu)造方法中,可以看到通過(guò)Lifecycle在ON_DESTROY事件中銷毀ViewModel。
public ComponentActivity() {
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
// 銷毀ViewModel
getViewModelStore().clear();
}
}
}
});
}
- Fragment中的銷毀
首先通過(guò)代碼跟蹤到ViewModelStore的clear()方法調(diào)用的地方,在FragmentManagerViewModel類的clearNonConfigState()方法中找到了ViewModel的銷毀邏輯。
如果繼續(xù)跟蹤代碼可以看到代碼的調(diào)用棧是 FragmentStateManager::destroy() -> (Fragment狀態(tài)切換)->FragmentManager::dispatchDestroy()->FragmentActivity::onDestory()。
void clearNonConfigState(@NonNull Fragment f) {
...
// Clear and remove the Fragment's ViewModelStore
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore != null) {
// 銷毀ViewModel
viewModelStore.clear();
mViewModelStores.remove(f.mWho);
}
}
Q:為什么不同的Fragment使用相同的Activity對(duì)象來(lái)獲取ViewModel,可以輕易的實(shí)現(xiàn)ViewModel共享?
它們其實(shí)共享的是Activity的ViewModel。因?yàn)椴煌腇ragment使用相同的Activity對(duì)象來(lái)獲取ViewModel,在創(chuàng)建ViewModel之前都會(huì)先從Activity提供的ViewModelStore中先查詢一遍是否已經(jīng)存在該ViewModel對(duì)象。
實(shí)現(xiàn)的邏輯在Fragment的activityViewModel()中:
inline fun <reified VM : ViewModel> Fragment.activityViewModels(
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
在activityViewModels()的實(shí)現(xiàn)中可以看到是requireActivity()獲取的viewModelStore。以此來(lái)實(shí)現(xiàn)共享ViewModel。
Q:ViewModel為什么可以實(shí)現(xiàn)屏幕旋轉(zhuǎn)而不銷毀?
1.Activity實(shí)現(xiàn)了ViewModelStoreOwner接口,創(chuàng)建了ViewModelStore對(duì)象。
public ViewModelStore getViewModelStore() {
...
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
2.當(dāng)Activity意外銷毀時(shí),onRetainNonConfigurationInstance函數(shù)被回調(diào),在此函數(shù)中對(duì)ViewModelStore對(duì)象進(jìn)行了保存。
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;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
3.當(dāng)Activity重建時(shí),onCreate方法中會(huì)先獲取getLastNonConfigurationInstance,如果其中的ViewModelStore對(duì)象不為空,就直接引用,不再重新創(chuàng)建ViewModelStore對(duì)象了。
ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders
字節(jié)高工面試靈魂7問(wèn):Android架構(gòu)組件—ViewModel這些知識(shí)點(diǎn)一定要掌握!