今天是2022年最后一天,祝大家元旦快樂。

ViewModel初識
ViewModel是Jetpack組件之一,它注重生命周期的方式存儲和管理界面的數(shù)據(jù),它是讓數(shù)據(jù)在屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存。通俗一點(diǎn)就是:手機(jī)屏幕發(fā)生旋轉(zhuǎn)后,數(shù)據(jù)依然還在。
ViewModel沒出來之前,怎么存取數(shù)據(jù)?
在ViewModel出現(xiàn)之前,一般屏幕發(fā)生旋轉(zhuǎn)時(shí)候,Activity生命周期會重新創(chuàng)建,我們會在onSaveInstance()里面保存數(shù)據(jù),然后在onCreate(Bundle saveInstance)里面取數(shù)據(jù),但是這個(gè)數(shù)據(jù)有弊端,必須要實(shí)現(xiàn)序列化和反序列化,并且這個(gè)數(shù)據(jù)不能太大。
class ViewModelActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//(2)取數(shù)據(jù)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
//(1)存數(shù)據(jù)
}
}
所以ViewModel就是為了解決這個(gè)問題的。
ViewModel的使用
(1)添加ViewModel依賴
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
(2)定義一個(gè)類繼承ViewModel(AndroidViewModel)即可
class MyViewModel : ViewModel() {
val updateLiveData by lazy { MutableLiveData<String>() }
}
(3)Activity創(chuàng)建ViewModel實(shí)例
class ViewModelActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var myViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
myViewModel.updateLiveData.observe(this) {
//update data
}
}
}
在Activity中,我們可以使用ViewModelProvider來得到 ViewMode的實(shí)例。
如果在ViewModel中,我們需要使用到上下文Context對象(toast 或者獲取系統(tǒng)服務(wù)等等),我們可以繼承AndroidViewModel來構(gòu)建ViewModel
class AndroidModel(app:Application): AndroidViewModel(app) {
}
此時(shí)這個(gè)AndroidModel的創(chuàng)建和上面的類似,也是用ViewModelProvider來獲得。
ViewModel常常結(jié)合LiveData使用,然后在我們的Activity或者Fragemnt中去監(jiān)聽LiveData的改變
然后去在Activity中做UI的更新邏輯,例如,我們需要根據(jù)網(wǎng)絡(luò)請求來決定是否彈出一個(gè)DialogFragment,我們的網(wǎng)絡(luò)請求放在ViewModel中,DialogFragment必須在Activity或者Fragment中彈出來(因?yàn)?code>DialogFragment的彈出不能使用Application作為Context),所以此時(shí)我們必須使用LiveData。當(dāng)網(wǎng)絡(luò)請求完成之后,我們改變LiveData的值,并且在Activity或者Fragment監(jiān)聽LiveData的變化,然后作出彈出DailogFragment的操作
在Fragment之間共享數(shù)據(jù)
現(xiàn)在的App中使用Fragment是很常見的,之前我們從Activity中向Fragment中傳遞數(shù)據(jù),我們使用Bundle來傳遞(在創(chuàng)建Fragment的時(shí)候),但是在Activity中如果需要動態(tài)傳遞(隨時(shí)傳遞)數(shù)據(jù)給Fragment,我們平常的做法可能是在Activity中持有Fragment的應(yīng)用,然后在Activity中去調(diào)用對于Fragment的某些方法傳遞數(shù)據(jù),或者利用通知系統(tǒng)(EventBus),但是我們?nèi)绻?code>BFragment中促使Activity中的數(shù)據(jù)改變,要通知到CFragment的Ui修改的話,目前的場景只能使用EventBus。當(dāng)然也可以使用我們這里的ViewModel了
class ShareViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
class ListFragment : Fragment() {
private lateinit var itemSelector: Selector
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: ShareViewModel?=null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model = ViewModelProvider(requireActivity()).get(ShareViewModel::class.java)
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
class DetailFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: ShareViewModel?=null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model = ViewModelProvider(requireActivity()).get(ShareViewModel::class.java)
model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
// Update the UI
})
}
在上面的兩個(gè)Fragment 在獲取ViewModel的時(shí)候 傳遞的都是requireActivity(),那么獲取到的ViewModel的實(shí)例其實(shí)就是同一個(gè)SharedViewModel,所以當(dāng)Activity 或者任何一個(gè)Fragment中 改變了SharedViewModel中LiveData的數(shù)據(jù),都會及時(shí)的通知到。這種方法有以下好處:
Activity 不需要執(zhí)行任何操作,也不需要對此通信有任何了解。
除了 SharedViewModel之外,Fragment不需要相互了解。如果其中一個(gè) Fragment消失,另一個(gè) Fragment將繼續(xù)照常工作。
每個(gè) Fragment都有自己的生命周期,而不受另一個(gè) Fragment的生命周期的影響。如果一個(gè)Fragment替換另一個(gè)Fragment,界面將繼續(xù)工作而沒有任何問題。
ViewModel的源碼解析

這里基本只需要知道onCleared()方法就行了,自定義ViewModel并重寫這個(gè)方法,講釋放資源的邏輯放在這個(gè)方法中就行
ViewModelProvider類
獲取ViewModel的實(shí)例時(shí),我們是使用ViewModelProvider來獲取的
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
創(chuàng)建ViewModelProvider的時(shí)候需要傳遞一個(gè)ViewModelStore 和一個(gè)Factory,而我們構(gòu)建的時(shí)候只傳遞了一個(gè)this(Activity),其實(shí)就是一個(gè)ViewModelStoreOwner,
AppCompatActivity -->FragmentActivity -->ComponentActivity --> ViewModelStoreOwner
有上面這樣一個(gè)繼承實(shí)現(xiàn)關(guān)系,我們的AppCompatActivity其實(shí)可以說是實(shí)現(xiàn)了ViewModelStoreOwner的,最終返回的是ComponentActivity中的mViewModelStore 關(guān)于Factory后面再講
@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.");
}
ensureViewModelStore();
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
這里就是獲取ViewModelStore的方法,可以看到在ensureViewModelStore方法中,我們會首先判斷mViewModelStore 是否為null,然后通過getLastNonConfigurationInstance()得到一個(gè)NonConfigurationInstances實(shí)例,這里其實(shí)就是當(dāng)Activity旋轉(zhuǎn)的時(shí)候ViewModel中的數(shù)據(jù)還會存在的奧秘,通過nc可以獲取重建之前的mViewModelStore,然后從ViewModelStore里面根據(jù)類名獲取ViewModel的實(shí)例,所以獲取到的ViewModel在旋轉(zhuǎn)前后其實(shí)是同一個(gè)實(shí)例,在我們的App系統(tǒng)configuration發(fā)生改變的時(shí)候 就會回調(diào)onRetainNonConfigurationInstance()這個(gè)方法
@SuppressWarnings("deprecation")
public final Object onRetainNonConfigurationInstance() {
// Maintain backward compatibility.
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;
}
//Activity中 的方法
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
這里就是將ViewModelStore進(jìn)行保存。 這里getLastNonConfigurationInstance方法 最后其實(shí)是返回Activity中的mLastNonConfigurationInstances 變量的activity對象,我們看看這mLastNonConfigurationInstances 在哪里賦值,我們知道,我們的Activity的啟動其實(shí)最終都會走到ActivityThread類中,當(dāng)我們啟動一個(gè)Activity的時(shí)候會執(zhí)行其中的 performLaunchActivity方法最終會調(diào)用到 Activity的attach方法,lastNonConfigurationInstances是存在ActivityClientRecord中的一個(gè)組件信息
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
ActivityClientRecord r = mActivities.get(token);
Class<? extends Activity> activityClass = null;
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
if (r != null) {
activityClass = r.activity.getClass();
r.activity.mConfigChangeFlags |= configChanges;
if (finishing) {
r.activity.mFinished = true;
}
performPauseActivityIfNeeded(r, "destroy");
if (!r.stopped) {
callActivityOnStop(r, false /* saveState */, "destroy");
}
if (getNonConfigInstance) {
try {
r.lastNonConfigurationInstances
= r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to retain activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
}
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnDestroy(r.activity);
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + safeToComponentShortString(r.intent) +
" did not call through to super.onDestroy()");
}
if (r.window != null) {
r.window.closeAllPanels();
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to destroy activity " + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
r.setState(ON_DESTROY);
}
schedulePurgeIdler();
// updatePendingActivityConfiguration() reads from mActivities to update
// ActivityClientRecord which runs in a different thread. Protect modifications to
// mActivities to avoid race.
synchronized (mResourcesManager) {
mActivities.remove(token);
}
StrictMode.decrementExpectedActivityCount(activityClass);
return r;
}
在屏幕旋轉(zhuǎn)造成的的Activity重建的時(shí)候 就會給lastNonConfigurationInstances這個(gè)變量賦值,這樣就能夠在Activity重建的時(shí)候 獲取到之前的ViewModel了。而我們的ViewModel中onClear方法什么時(shí)候執(zhí)行呢,在我們的ComponetActivity構(gòu)方法中
public ComponentActivity() {
// ......省略部分代碼
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
上面注冊了一個(gè)Lifecycle的監(jiān)聽,在我們的Activity在onDestory之后 并且isChangingConfigurations()為false的時(shí)候,才會去執(zhí)行getViewModelStore().clear(); 的操作間接調(diào)用到ViewModel的onCleared()方法
get()獲取ViewModel
在這里通過get方法創(chuàng)建ViewModel傳入的參數(shù)是 所需要創(chuàng)建的ViewModel的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");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@SuppressWarnings("unchecked")
@NonNull
@MainThread
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 {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
最終通過下面的get方法獲取ViewModel,當(dāng)我們從ViewModelStore 根據(jù)key值去獲取ViewModel為null的時(shí)候,如果為null 就是用Factory進(jìn)行創(chuàng)建。所以后面我們也可以定義自己的Factory 來創(chuàng)建ViewModel
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í)就是一個(gè) HashMap存放了ViewModel,主要是ViewModel的存取.
總結(jié)
1.現(xiàn)在的Activity底層已經(jīng)繼承了 ComponentActivity ,并實(shí)現(xiàn)了 ViewModelStoreOwner 接口,通過ViewModelProvider使用默認(rèn)工廠 創(chuàng)建了 viewModel,并通過唯一Key值 進(jìn)行標(biāo)識,
存儲到了 ViewModelStore中。等下次需要的時(shí)候即可通過唯一Key值進(jìn)行獲取。
2.由于ComponentActivity 實(shí)現(xiàn)了ViewModelStoreOwner接口,實(shí)現(xiàn)了 getViewModelStore方法,當(dāng)屏幕旋轉(zhuǎn)的時(shí)候,會先調(diào)用 onRetainNonConfigurationInstance()方法
將viewModelStore保存起來,當(dāng)屏幕旋轉(zhuǎn)之后,會在ensureViewModel()方法中再調(diào)用 getLastNonConfigurationInstance方法將數(shù)據(jù)恢復(fù),如果為空的話,會重新創(chuàng)建viewModelStore ,
并存儲在全局中,以便以下次發(fā)生變化的時(shí)候,能夠通過onRetainNonConfigurationInstance 保存起來。
3.最后當(dāng)頁面銷毀并且沒有配置更改的時(shí)候,會將viewModelStore中的數(shù)據(jù) 進(jìn)行清除操作。