Android?Jetpack庫(kù)剖析之ViewModel組件篇
前言
今天讓我們一起去探究一下ViewModel的實(shí)現(xiàn)原理,描述的不對(duì)或不足還請(qǐng)海涵,僅作為參考
ViewModel簡(jiǎn)介
ViewModel是一個(gè)可感知Activity或Fragment生命周期的一個(gè)架構(gòu)組件,當(dāng)視圖銷毀,數(shù)據(jù)也會(huì)被清除,所以它的本質(zhì)就是用來(lái)存儲(chǔ)與視圖相關(guān)的數(shù)據(jù),讓視圖顯示控制與數(shù)據(jù)分離,即使界面配置發(fā)生改變數(shù)據(jù)也不會(huì)被銷毀,通常配合LiveData使用
ViewModel用法
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(LayoutInflater.from(baseContext))
setContentView(binding.root)
//獲取ViewModel實(shí)例
val viewModel: TextViewModel = ViewModelProvider(this).get(TextViewModel::class.java)
//訂閱數(shù)據(jù)
viewModel.liveData.observe(this, { println(it) })
//調(diào)用函數(shù)
viewModel.test()
}
class TextViewModel : ViewModel() {
val liveData = MediatorLiveData<String>()
fun test() {
liveData.postValue("Hello")
}
}
}1,使用ViewModelProvider獲取ViewModel實(shí)例
2,訂閱VIewModel的LiveData
3,調(diào)用ViewModel的方法
構(gòu)造ViewModelProvider過(guò)程做了什么
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
1,當(dāng)我們創(chuàng)建ViewModelProvider的時(shí)候需要傳入一個(gè)ViewModelStoreOwner對(duì)象,ViewModelStoreOwner是負(fù)責(zé)提供ViewModelStore對(duì)象的, 而ComponentActivity實(shí)現(xiàn)了這個(gè)接口,所以我們默認(rèn)傳當(dāng)前的Activity即可
2,首先判斷是否有默認(rèn)的ViewModel工廠,如果沒(méi)有就創(chuàng)建一個(gè)Factory
3,F(xiàn)actory是用來(lái)創(chuàng)建ViewModel的,ViewModelStore是用來(lái)存儲(chǔ)ViewModel的
調(diào)用get()方法是如何構(gòu)建ViewModel
@NonNull
@MainThread
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");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//通過(guò)key到ViewModelStore中取
ViewModel viewModel = mViewModelStore.get(key);
//如果取到ViewModel 代表已經(jīng)創(chuàng)建過(guò)這個(gè)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.
}
}
//通過(guò)Factor利用反射創(chuàng)建一個(gè)實(shí)例
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
//把ViewModel實(shí)例存儲(chǔ)到ViewModelStore中
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}1,當(dāng)我們調(diào)用get()方法時(shí)會(huì)先獲取類名,然后生成一個(gè)唯一的key
2,先通過(guò)key到ViewModelStore中取ViewModel,如果不為空代表已經(jīng)創(chuàng)建過(guò)這個(gè)ViewModel的實(shí)例,直接返回這個(gè)實(shí)例
3,如果為空就通過(guò)工廠利用java反射機(jī)制創(chuàng)建一個(gè)實(shí)例,通過(guò)鍵值對(duì)形式保存到ViewModelStore中,返回實(shí)例,看到這里是不是對(duì)為什么多個(gè)fragment可以共享同一個(gè)ViewModel的疑問(wèn)豁然開朗了,因?yàn)镕ragment是依附于Activity之上的,在我們構(gòu)建ViewModelProvider的時(shí)候傳入同一個(gè)Activity,那么ViewModelProvider得到的ViewModelStore是同一個(gè),在我們調(diào)用get()方法時(shí)就能通過(guò)key到ViewModelStore中取到同一個(gè)ViewModel實(shí)例,說(shuō)白了就是共用Activity的ViewModel
Activity配置發(fā)生改變?nèi)绾尉彺鎂iewModelStore
ActivityThread{
private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
PendingTransactionActions pendingActions, boolean startsNotResumed,
Configuration overrideConfig, String reason) {
// Preserve last used intent, it may be set from Activity#setIntent().
final Intent customIntent = r.activity.mIntent;
// Need to ensure state is saved.
if (!r.paused) {
performPauseActivity(r, false, reason, null /* pendingActions */);
}
if (!r.stopped) {
callActivityOnStop(r, true /* saveState */, reason);
}
//銷毀Activity
handleDestroyActivity(r.token, false, configChanges, true, reason);
//啟動(dòng)Activity
handleLaunchActivity(r, pendingActions, customIntent);
}
}1,當(dāng)我們切換橫豎屏的時(shí)候,ActivityThread會(huì)接收到RELAUNCH_ACTIVITY消息,會(huì)調(diào)用自身的handleRelaunchActivityInner(),這個(gè)方法里面有一個(gè)參數(shù)r,類型是ActivityClientRecord,我們每打開一個(gè)Activity,ActivityThread就會(huì)生成這么個(gè)對(duì)象來(lái)記錄我們打開的Activity并保存起來(lái)
2,handleRelaunchActivityInner()這個(gè)方法里調(diào)用了handleDestroyActivity()方法去銷毀我們的Activity
ActivityThread{
@Override
public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
boolean getNonConfigInstance, String reason) {
//執(zhí)行銷毀Activity
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance, reason);
}
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
//通過(guò)token獲取Activity的記錄
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
//是否需要獲取配置實(shí)例
if (getNonConfigInstance) {
try {
//調(diào)用Activity的retainNonConfigurationInstances方法獲取配置實(shí)例
r.lastNonConfigurationInstances
= r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
}
}
r.setState(ON_DESTROY);
}
//通過(guò)token移除這條Activity的記錄
synchronized (mResourcesManager) {
mActivities.remove(token);
}
return r;
}
}3,handleDestroyActivity()則直接調(diào)用了performDestroyActivity()方法去銷毀Activity,核心部分就是調(diào)用了Activity的retainNonConfigurationInstances()方法獲取了配置實(shí)例并復(fù)制給了ActivityClientRecord,把NonConfigurationInstances實(shí)例保存起來(lái)
Activity{
NonConfigurationInstances retainNonConfigurationInstances() {
//獲取NonConfigurationInstances對(duì)象
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
mFragments.doLoaderStart();
mFragments.doLoaderStop(true);
ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
//創(chuàng)建NonConfigurationInstances實(shí)例
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
}
ComponentActivity{
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
//獲取ViewModelStore
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;
}
//創(chuàng)建NonConfigurationInstances實(shí)例
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
}4, 通過(guò)查閱源碼,一層一層的往下剖析,ActivityThread是通過(guò)這樣的調(diào)用鏈來(lái)獲取我們的ViewModelStore實(shí)例并保存在ActivityClientRecord中的
Activity重建后如何恢復(fù)ViewModelStore
ActivityThread{
private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
PendingTransactionActions pendingActions, boolean startsNotResumed,
Configuration overrideConfig, String reason) {
// Preserve last used intent, it may be set from Activity#setIntent().
final Intent customIntent = r.activity.mIntent;
// Need to ensure state is saved.
if (!r.paused) {
performPauseActivity(r, false, reason, null /* pendingActions */);
}
if (!r.stopped) {
callActivityOnStop(r, true /* saveState */, reason);
}
//銷毀Activity
handleDestroyActivity(r.token, false, configChanges, true, reason);
//啟動(dòng)Activity
handleLaunchActivity(r, pendingActions, customIntent);
}
}1,當(dāng)handleDestroyActivity執(zhí)行完畢就已經(jīng)把ViewModelStore的實(shí)例獲取到并存放到ActivityClientRecord中,此時(shí)就開始執(zhí)行handleLaunchActivity()方法來(lái)啟動(dòng)activity
2,handleLaunchActivity()這個(gè)方法也需要ActivityClientRecord這個(gè)參數(shù),而此時(shí)ActivityClientRecord這個(gè)對(duì)象正是經(jīng)過(guò)handleDestroyActivity()這個(gè)方法獲取并保存了ViewModelStore 實(shí)例的對(duì)象
3,handleLaunchActivity()則調(diào)用了performLaunchActivity()方法來(lái)啟動(dòng)Activity
ActivityThread{
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
//去啟動(dòng)Activity
final Activity a = performLaunchActivity(r, customIntent);
return a;
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(activity);
//調(diào)用當(dāng)前打開的Activity的attach()方法
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
r.activity = activity;
}
r.setState(ON_CREATE);
//保存這條Activity記錄
synchronized (mResourcesManager) {
mActivities.put(r.token, r);
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
}
return activity;
}
}4,通過(guò)代碼發(fā)現(xiàn)performLaunchActivity調(diào)用了當(dāng)前正在打開的Activity的attach方法,而這個(gè)方法需要一個(gè)NonConfigurationInstances類型的參數(shù),這個(gè)參數(shù)里面就有我們的ViewModelStore實(shí)例
Activity{
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
//賦值給mLastNonConfigurationInstances
mLastNonConfigurationInstances = lastNonConfigurationInstances;
setAutofillOptions(application.getAutofillOptions());
setContentCaptureOptions(application.getContentCaptureOptions());
}
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
}
ComponentActivity{
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) {
//先去lastNonConfigurationInstance中取,沒(méi)有再創(chuàng)建
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
}5,在attach方法里就把這個(gè)參數(shù)賦值給mLastNonConfigurationInstances,當(dāng)我們獲取ViewModelStore實(shí)例的時(shí)候,就會(huì)先去mLastNonConfigurationInstances中取,如果沒(méi)有再自己創(chuàng)建一個(gè)ViewModelStore實(shí)例,到這里整個(gè)調(diào)用鏈就搞明白了
生命周期綁定
ComponentActivity{
public ComponentActivity(){
//訂閱生命周期,當(dāng)生命周期==ON_DESTROY,清除ViewModel數(shù)據(jù)
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();
}
}
}
});
}
}
ViewModelStore{
public final void clear() {
//遍歷所有ViewModel并調(diào)用其clear()方法清空數(shù)據(jù)
for (ViewModel vm : mMap.values()) {
vm.clear();
}
//清空所有ViewModel
mMap.clear();
}
}總結(jié)
1,ComponentActivity實(shí)現(xiàn)了ViewModelStoreOwner接口并實(shí)現(xiàn)了其抽象方法getViewModelStore()
2,我們通過(guò)ViewModelProvider使用默認(rèn)工廠創(chuàng)建了ViewModel,通過(guò)唯一key值進(jìn)行標(biāo)識(shí)并保存到ViewModelStore中
3,當(dāng)切換橫豎屏的時(shí)候ActivityThread接收到RELAUNCH_ACTIVITY消息,就會(huì)調(diào)用Activity的retainNonConfigurationInstances()方法獲取我們的ViewModelStore實(shí)例并保存起來(lái)
4,當(dāng)Activity啟動(dòng)并調(diào)用attach()方法時(shí)就將切換橫豎屏前的ViewModel恢復(fù)過(guò)來(lái)
5,當(dāng)我們獲取ViewModelStore實(shí)例的時(shí)候會(huì)調(diào)用先getLastNonConfigurationInstance()方法去取ViewModelStore,如果為null就會(huì)重新創(chuàng)建ViewModelStore并存儲(chǔ)在全局中
6,當(dāng)生命周期發(fā)生改變,并且狀態(tài)為ON_DESTROY,清除ViewModel數(shù)據(jù)以及實(shí)例
到此這篇關(guān)于Android Jetpack庫(kù)剖析之ViewModel組件篇的文章就介紹到這了,更多相關(guān)Android ViewModel內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
android實(shí)現(xiàn)簡(jiǎn)易登錄注冊(cè)界面及邏輯設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)簡(jiǎn)易登錄注冊(cè)界面及邏輯設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
android 手機(jī)截取長(zhǎng)屏實(shí)例代碼
本篇文章主要介紹了android 手機(jī)截取長(zhǎng)屏實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
android onTouchEvent處理機(jī)制總結(jié)(必看)
下面小編就為大家?guī)?lái)一篇android onTouchEvent處理機(jī)制總結(jié)(必看)小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
Android ShimmerLayout實(shí)現(xiàn)微光效果解析
這篇文章主要為大家詳細(xì)介紹了Android ShimmerLayout實(shí)現(xiàn)微光效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
android 圖片操作(縮放移動(dòng)) 實(shí)例代碼
android 圖片操作(縮放移動(dòng)) 實(shí)例代碼,需要的朋友可以參考一下2013-06-06
Android仿微信清理內(nèi)存圖表動(dòng)畫(解決surfaceView屏幕閃爍問(wèn)題)demo實(shí)例詳解
本文通過(guò)實(shí)例代碼給大家講解android仿微信清理內(nèi)存圖表動(dòng)畫(解決surfaceView屏幕閃爍問(wèn)題)的相關(guān)資料,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09
Android MessageQueue消息隊(duì)列主要作用詳解
Android 消息機(jī)制主要指的是 Handler 的運(yùn)行機(jī)制及其所依賴的 MessageQueue 和 Looper 的工作過(guò)程,Handler、MessageQueue、Looper組成一個(gè)相互聯(lián)系的整體。本文先從 MessageQueue 的源碼來(lái)說(shuō)明其實(shí)現(xiàn)原理2023-02-02
詳解Flutter自定義應(yīng)用程序內(nèi)鍵盤的實(shí)現(xiàn)方法
本文將展示如何利用Flutter創(chuàng)建自定義鍵盤小部件,用于在自己的應(yīng)用程序中的Flutter TextField中輸入文本,感興趣的小伙伴可以了解一下2022-06-06
基于Android實(shí)現(xiàn)顏色漸變動(dòng)畫效果
本文主要給大家介紹了Android實(shí)現(xiàn)顏色漸變動(dòng)畫效果,實(shí)現(xiàn)這樣的一個(gè)動(dòng)畫漸變的效果很簡(jiǎn)單,只需要兩步,第一步用GradientDrawable實(shí)現(xiàn)兩個(gè)顏色之間的漸變效果,第二步用屬性動(dòng)畫實(shí)現(xiàn)顏色變化的過(guò)程,需要的朋友可以參考下2024-01-01

