看了網(wǎng)上很多對(duì)于ViewModel的講解蚜退,對(duì)比了官方的使用闰靴,自覺(jué)有點(diǎn)官方譯文科普的意思,即使看很多钻注,仍舊沒(méi)有醍醐灌頂?shù)母杏X(jué)蚂且,于是,深入源碼分析后幅恋,便想將對(duì)于ViewModel的使用以及定位做一些簡(jiǎn)單的記錄杏死,如與編者有不一樣的看法,希望在評(píng)論區(qū)一起討論捆交。文章旨在拋磚引玉淑翼,并無(wú)教學(xué)之意。
對(duì)于ViewModel的官方介紹:
ViewModel 類(lèi)旨在以注重生命周期的方式存儲(chǔ)和管理界面相關(guān)的數(shù)據(jù)品追。ViewModel類(lèi)讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存玄括。
從介紹來(lái)看,仿佛ViewModel有自己的生命周期肉瓦?看到有些文章也是這樣描述遭京,提到:ViewModel會(huì)維護(hù)自己的生命周期。那么泞莉,它真的會(huì)維護(hù)自己的生命周期嗎哪雕?
問(wèn)題一:ViewModel生命周期?
首先鲫趁,ViewModel是如何創(chuàng)建的斯嚎?
class MainViewModel : ViewModel() {}
class MainActivity : ComponentActivity() {
private val model: MainViewModel by viewModels()
}
我通過(guò)官方給的委托函數(shù)進(jìn)行了ViewModel的初始化蹲盘,直接跟進(jìn)去查看ViewModel的創(chuàng)建笔喉,可以找到關(guān)鍵的創(chuàng)建語(yǔ)句,
ViewModelProvider(store, factory).get(MainViewModel::class.java)
直接跟到get方琺的實(shí)現(xiàn)
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
……略過(guò)
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
if (viewModel != null) {
}
}
if (mFactory instanceof KeyedFactory) {
//走到這里,記住create方法
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
//請(qǐng)記住這個(gè)東西
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
那么可以看出來(lái)ViewModelProvider的兩個(gè)參數(shù)
- mViewModelStore :ViewModel的復(fù)用有關(guān)
- Factory :與創(chuàng)建有關(guān)
先不管復(fù)用規(guī)則实撒,找到當(dāng)前創(chuàng)建ViewModel的Factory幽崩,找到委托方法的factory可以看到
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
找到ComponentActivity的默認(rèn)Factory->SavedStateViewModelFactory
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
//順便看一下它的構(gòu)造方法
public SavedStateViewModelFactory(@Nullable Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
//這里很關(guān)鍵
mFactory = application != null
? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
: ViewModelProvider.NewInstanceFactory.getInstance();
}
可以看到苦始,在創(chuàng)建SavedStateViewModelFactory的同時(shí),又看到了兩個(gè)Factory慌申。
暫且不管陌选,追一下這個(gè)默認(rèn)的Factory是如何執(zhí)行Create方法的
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if (isAndroidViewModel && mApplication != null) {
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
//這句注釋很有意思,留神蹄溉。
// doesn't need SavedStateHandle
if (constructor == null) {
return mFactory.create(modelClass);
}
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
try {
T viewmodel;
if (isAndroidViewModel && mApplication != null) {
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
viewmodel = constructor.newInstance(controller.getHandle());
}
return viewmodel;
}
這段代碼是在尋找ViewModel的構(gòu)造器咨油,可以看到這段代碼的最后是要調(diào)用ViewModel的兩個(gè)帶參構(gòu)造函數(shù)。
這里是個(gè)疑點(diǎn)柒爵,為什么要傳遞參數(shù)呢?為什么會(huì)固定有一個(gè)參數(shù)役电?
先保留疑問(wèn),繼續(xù)看可以發(fā)現(xiàn)棉胀,我創(chuàng)建的ViewModel走了在SavedStateViewModelFactory構(gòu)造函數(shù)中創(chuàng)建的Factory法瑟,這里發(fā)現(xiàn)AndroidViewModelFactory派生自NewInstanceFactory冀膝,再看一下AndroidViewModelFactory的create函數(shù)是如何實(shí)現(xiàn)的
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
}
return super.create(modelClass);
}
}
發(fā)現(xiàn)AndroidViewModelFactory會(huì)判斷AndroidViewModel是不是modelClass超類(lèi)或超接口,如果是霎挟,則直接調(diào)用構(gòu)造函數(shù)的Application參數(shù)方法窝剖,
如果不是
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return modelClass.newInstance();
}
直接創(chuàng)建。
那么ViewModel就創(chuàng)建完畢了酥夭,emm...等等赐纱,我不是要找它的生命周期嗎?為什么沒(méi)有看到有關(guān)生命周期的代碼熬北?
難道奧秘都在剛才遺忘的mViewModelStore中疙描?看一下它的代碼
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());
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
這。讶隐。起胰。不就是個(gè)容器嗎?它在哪里創(chuàng)建的巫延?再回顧一下委托函數(shù)
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
哦待错,可以看到在我注冊(cè)的Activity中有一個(gè)viewModelStore,那么它是如何創(chuàng)建的?
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.");
}
ensureViewModelStore();
return mViewModelStore;
}
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
這里的getLastNonConfigurationInstance()只需要知道烈评,這個(gè)是一種界面恢復(fù)與保存的API,跟它一樣的有我們熟知的onSaveInstanceState / onRestoreInstanceState犯建,如果你感興趣可以查閱資料讲冠,不過(guò)這個(gè)Api在新的Sdk中已經(jīng)不建議使用了,這里一會(huì)我們繼續(xù)談适瓦。
所以說(shuō)竿开,ViewModelStore保存了每個(gè)ViewModel的實(shí)例,在頁(yè)面重構(gòu)時(shí)做了處理玻熙。讓每個(gè)界面的ViewModelStore不會(huì)因?yàn)橹貥?gòu)而消失否彩。那么,它怎樣才能消失呢嗦随?難道ViewModel會(huì)一直存在嗎列荔?
當(dāng)然不是,ViewModelStore明明有clear()方法枚尼,那么它的調(diào)用時(shí)機(jī)是怎樣的呢贴浙?
查找了下,第一個(gè)正是我當(dāng)前想要知道的署恍,它對(duì)應(yīng)的代碼如下
public ComponentActivity() {
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
mContextAwareHelper.clearAvailableContext();
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
所以崎溃,在創(chuàng)建ComponentActivity的時(shí)候注冊(cè)了監(jiān)聽(tīng)當(dāng)生命周期到ON_DESTORY的時(shí)候并且不是更改配置,就清空Store盯质。
分析完畢袁串。
結(jié)論:ViewModel并沒(méi)有自己的生命周期概而,官方所謂的能在界面變動(dòng)時(shí)不丟失數(shù)據(jù),也是因?yàn)閂iewModel的容器在對(duì)應(yīng)的邏輯做了保存處理囱修。
問(wèn)題二:既然如此赎瑰,那么我可不可以制作一個(gè)由我控制生命周期的ViewModel呢?
當(dāng)然可以
class AppViewModelStore : ViewModelStoreOwner , LifecycleEventObserver{
var store: ViewModelStore = ViewModelStore()
override fun getViewModelStore(): ViewModelStore {
return store
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
//在Life走到ON_PAUSE清理蔚袍。舉例說(shuō)明乡范,不建議使用。
if (event == Lifecycle.Event.ON_PAUSE) {
store.clear()
}
}
}
//使用
ViewModelProvider(AppViewModelStore()).get(MainViewModel::class.java)
問(wèn)題三:我可不可以創(chuàng)建一個(gè)自定義參數(shù)的ViewModel呢啤咽?
分析源碼可以知道晋辆,store負(fù)責(zé)ViewModel保存與銷(xiāo)毀,F(xiàn)actory負(fù)責(zé)創(chuàng)建宇整,所以直接重寫(xiě)Factory即可瓶佳。
class MyVMFactory : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainViewModel(參數(shù)) as T
}
}
//使用
ViewModelProvider(AppViewModelStore(),MyVMFactory()).get(MainViewModel::class.java)
只需要像源碼那樣創(chuàng)建就可以,只要把握ViewModelStore的保存與銷(xiāo)毀即可鳞青。
到這里霸饲,不免有點(diǎn)失落,viewModel就這臂拓?
google真的只是幫開(kāi)發(fā)者做了這些嗎厚脉?就當(dāng)我準(zhǔn)備結(jié)束的時(shí)候,突然想起胶惰,在分析ViewModel生命周期中的一段注釋
/**
* Use this instead of {#onRetainNonConfigurationInstance()}.
* Retrieve later with {#getLastCustomNonConfigurationInstance()}.
*
* @deprecated Use a { androidx.lifecycle.ViewModel} to store non config state.
*/
是的傻工,在getLastCustomNonConfigurationInstance()方法與onRetainNonConfigurationInstance()方法上的注釋?zhuān)屛矣肰iewModel去做配置項(xiàng)的東西,相當(dāng)于孵滞,onSaveInstanceState與onRestoreInstanceState中捆,可以用ViewModel直接配置。
看到這句話你明白了嗎坊饶?
我舉一個(gè)開(kāi)發(fā)中的例子:
當(dāng)用戶的手機(jī)在后臺(tái)很久之后泄伪,系統(tǒng)會(huì)回收應(yīng)用的資源,導(dǎo)致一些數(shù)據(jù)丟失匿级,打開(kāi)應(yīng)用會(huì)丟失數(shù)據(jù)或者崩潰蟋滴,因此很多的開(kāi)發(fā)者會(huì)把一部分?jǐn)?shù)據(jù)做本地持久化處理,沒(méi)有持久化處理的數(shù)據(jù)需要用onSaveInstanceState與onRestoreInstanceState進(jìn)行保存與恢復(fù)根蟹。然后項(xiàng)目的代碼變成了這樣
override fun onSaveInstanceState(outState: Bundle) {
outState.putBoolean("MBoolean", true)
outState.putInt("MInt", 1)
outState.putString("MString", "save Info")
```
省略
```
super.onSaveInstanceState(outState)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
savedInstanceState.getBoolean("MBoolean", true)
savedInstanceState.getInt("MInt", 1)
savedInstanceState.getString("MString", "save Info")
```
省略
```
super.onRestoreInstanceState(savedInstanceState)
}
是的脓杉,這樣不容易維護(hù),大量的代碼讓人摸不著頭腦简逮,因此很多應(yīng)用都統(tǒng)一讓用戶重新加載球散。
那么用ViewModel怎么解決了這個(gè)問(wèn)題呢?
class MainViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
fun getType(){
```
業(yè)務(wù)邏輯
```
savedStateHandle.get<String>("sKey")
}
fun putMessage(){
```
業(yè)務(wù)邏輯
```
savedStateHandle["sKey"] = "save info"
}
}
只需要在ViewModel的構(gòu)造器中添加SavedStateHandle參數(shù)即可散庶。
它的創(chuàng)建是在我的第一個(gè)疑惑點(diǎn)蕉堰,在分析Factory的創(chuàng)建代碼中對(duì)于構(gòu)造器的選擇凌净。
當(dāng)一次業(yè)務(wù)代碼完成后即可選擇是否要將業(yè)務(wù)內(nèi)容保存下來(lái),當(dāng)系統(tǒng)因內(nèi)存不足回收應(yīng)用數(shù)據(jù)后屋讶,應(yīng)用仍然能第一時(shí)間回到當(dāng)前界面冰寻。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),只需要選擇保存與回調(diào)的數(shù)據(jù)皿渗。
具體代碼請(qǐng)參考
SavedStateViewModelFactory.java
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
……省略
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
……
}
因篇幅問(wèn)題斩芭,不做詳細(xì)分析。
其實(shí)這些東西就是在開(kāi)發(fā)者文檔中的一些用法乐疆,只是我從一個(gè)點(diǎn)走過(guò)了全程划乖,在我沒(méi)有閱讀文檔情況下,我發(fā)現(xiàn)了這些用法挤土,于是便去文檔中進(jìn)行查找琴庵。地址在這里
最后
我突然想到,如果這樣那ViewModel的構(gòu)造函數(shù)豈不是無(wú)法自定義了仰美?并且自定義ViewModelStore也不能用了迷殿?
但是,反過(guò)來(lái)想想咖杂,Google也沒(méi)有說(shuō)ViewModel支持這些做法庆寺,而且,我的一些想法明顯是在破壞ViewModel自身的設(shè)計(jì)诉字。難怪Google由最初的教大家自定義Factory傳遞參數(shù)到只字不提止邮。
結(jié)論
- ViewModel生命周期?
ViewModel本身沒(méi)有生命周期奏窑,裝載ViewModel的容器ViewModelStore有生命周期。 - 我可不可以制作一個(gè)由我控制生命周期的ViewModel呢屈扎?
可以埃唯,但是創(chuàng)建了之后將失去ViewModel的意義。 - 我可不可以創(chuàng)建一個(gè)自定義參數(shù)的ViewModel呢鹰晨?
可以墨叛,但是創(chuàng)建了之后將失去ViewModel的優(yōu)點(diǎn)。 - ViewModel到底是什么模蜡?
正確使用它是有生命的容器
錯(cuò)誤使用它是數(shù)據(jù)容器漠趁。