嗨,大家好,面試真題系列又來了,今天我們說說MVVM架構里的兩大組件:ViewModel和LiveData,
還是老樣子,提出問題,做出解答,
-
ViewModel 是什么?
-
ViewModel 為什么被設計出來,解決了什么問題?
-
說說ViewModel原理,
-
LiveData 是什么?
-
LiveData 為什么被設計出來,解決了什么問題?
-
說說LiveData原理,
ViewModel 是什么,說說你所理解的ViewModel?
如果看過我上一篇文章的小伙伴應該都有所了解,ViewModel是MVVM架構的一個層級,用來聯系View和model之間的關系,而我們今天要說的就是官方出的一個框架——ViewModel,
ViewModel 類旨在以注重生命周期的方式存盤和管理界面相關的資料
官方是這么介紹的,這里面有兩個資訊:
- 注重生命周期的方式,
由于ViewModel的生命周期是作用于整個Activity的,所以就節省了一些關于狀態維護的作業,最明顯的就是對于螢屏旋轉這種情況,以前對資料進行保存讀取,而ViewModel則不需要,他可以自動保留資料,
其次,由于ViewModel在生命周期內會保持區域單例,所以可以更方便Activity的多個Fragment之間通信,因為他們能獲取到同一個ViewModel實體,也就是資料狀態可以共享了,
- 存盤和管理界面相關的資料,
ViewModel層的根本職責,就是負責維護界面上UI的狀態,其實就是維護對應的資料,因為資料會最終體現到UI界面上,所以ViewModel層其實就是對界面相關的資料進行管理,存盤等操作,
ViewModel 為什么被設計出來,解決了什么問題?
- 在
ViewModel組件被設計出來之前,MVVM又是怎么實作ViewModel這一層級的呢?
其實就是自己撰寫類,然后通過介面,內部依賴實作View和資料的雙向系結,
所以Google出這個ViewModel組件,無非就是為了規范MVVM架構的實作,并盡量讓ViewModel這一層級只觸及到業務代碼,不去關心VIew層級的參考等,然后配合其他的組件,包括livedata,databindingrang等讓MVVM架構更加完善,規范,健碩,
- 解決了什么問題呢?
其實上面已經說過一些了,比如:
1)不會因為螢屏旋轉而銷毀,減少了維護狀態的作業
2)由于在作用域內單一實體的特性,使得多個fragment之間可以方便通信,并且維護同一個資料狀態,
3)完善了MVVM架構,使得解耦更加純粹,
說說ViewModel原理,
- 首先說說是怎么保存生命周期
ViewModel2.0之前呢,其實原理是在Activity上add一個HolderFragment,然后設定setRetainInstance(true)方法就能讓這個Fragment在Activity重建時存活下來,也就保證了ViewModel的狀態不會隨Activity的狀態所改變,
2.0之后,其實是用到了Activity的onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()這兩個方法,相當于在橫豎屏切的時候會保存ViewModel的實體,然后恢復,所以也就保證了ViewModel的資料,
- 再說說怎么保證作用域內唯一實體
首先,ViewModel的實體是通過反射獲取的,反射的時候帶上application的背景關系,這樣就保證了不會持有Activity或者Fragment等View的參考,然后實體創建出來會保存到一個ViewModelStore容器里面,其實也就是一個集合類,這個ViewModelStore 類其實就是保存在界面上的那個實體,而我們的ViewModel就是里面的一個集合類的子元素,
所以我們每次獲取的時候,首先看看這個集合里面有無我們的ViewModel,如果沒有就去實體化,如果有就直接拿到實體使用,這樣就保證了唯一實體,最后在界面銷毀的時候,會去執行ViewModelStore的clear方法,去清除集合里面的ViewModel資料,一小段代碼說明下:
public <T extends ViewModel> T get(Class<T> modelClass) {
// 先從ViewModelStore容器中去找是否存在ViewModel的實體
ViewModel viewModel = mViewModelStore.get(key);
// 若ViewModel已經存在,就直接回傳
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
}
// 若不存在,再通過反射的方式實體化ViewModel,并存盤進ViewModelStore
viewModel = modelClass.getConstructor(Application.class).newInstance(mApplication);
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mViewModelStore != null && !isChangingConfigurations()) {
mViewModelStore.clear();
}
}
LiveData 是什么?
LiveData 是一種可觀察的資料存盤器類,與常規的可觀察類不同,LiveData 具有生命周期感知能力,意指它遵循其他應用組件(如 Activity、Fragment 或 Service)的生命周期,這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態的應用組件觀察者,
官方介紹如下,其實說的比較清楚了,主要作用在兩點:
-
資料存盤器類,也就是一個用來存盤資料的類, -
可觀察,這個資料存盤類是可以觀察的,也就是比一般的資料存盤類多了這么一個功能,對于資料的變動能進行回應,
主要思想就是用到了觀察者模式思想,讓觀察者和被觀察者解耦,同時還能感知到資料的變化,所以一般被用到ViewModel中,ViewModel負責觸發資料的更新,更新會通知到LiveData,然后LiveData再通知活躍狀態的觀察者,
var liveData = https://www.cnblogs.com/jimuzz/p/MutableLiveData()
liveData.observe(this, object : Observer {
override fun onChanged(t: String?) {
}
})
liveData.setVaile("xixi")
//子執行緒呼叫
liveData.postValue("test")
LiveData 為什么被設計出來,解決了什么問題?
LiveData作為一種觀察者模式設計思想,常常被和Rxjava一起比較,觀察者模式的最大好處就是事件發射的上游 和 接收事件的下游 互不干涉,大幅降低了互相持有的依賴關系所帶來的強耦合性,
其次,LiveData還能無縫銜接到MVVM架構中,主要體現在其可以感知到Activity等生命周期,這樣就帶來了很多好處:
-
不會發生記憶體泄漏
觀察者會系結到Lifecycle物件,并在其關聯的生命周期遭到銷毀后進行自我清理, -
不會因 Activity 停止而導致崩潰
如果觀察者的生命周期處于非活躍狀態(如回傳堆疊中的 Activity),則它不會接收任何 LiveData 事件, -
自動判斷生命周期并回呼方法
如果觀察者的生命周期處于STARTED或RESUMED狀態,則 LiveData 會認為該觀察者處于活躍狀態,就會呼叫onActive方法,否則,如果 LiveData 物件沒有任何活躍觀察者時,會呼叫onInactive()方法,
說說LiveData原理,
說到原理,其實就是兩個方法:
- 訂閱方法,也就是
observe方法,通過該方法把訂閱者和被觀察者關聯起來,形成觀察者模式,
簡單看看原始碼:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//...
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
public V putIfAbsent(@NonNull K key, @NonNull V v) {
Entry<K, V> entry = get(key);
if (entry != null) {
return entry.mValue;
}
put(key, v);
return null;
}
這里putIfAbsent方法是講生命周期相關的wrapper和觀察者observer作為key和value存到了mObservers中,
- 回呼方法,也就是
onChanged方法,通過改變存盤值,來通知到觀察者也就是呼叫onChanged方法,從改變存盤值方法setValue看起:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = https://www.cnblogs.com/jimuzz/p/value;
dispatchingValue(null);
}
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
//...
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
這一套下來邏輯還是比較簡單的,遍歷剛才的map——mObservers,然后找到觀察者observer,如果觀察者不在活躍狀態(活躍狀態,也就是可見狀態,處于 STARTED 或 RESUMED狀態),則直接回傳,不去通知,否則正常通知到觀察者的onChanged方法,
當然,如果想任何時候都能監聽到,都能獲取回呼,呼叫observeForever方法即可,
參考
viewmodel推薦閱讀
livedata推薦閱讀
拜拜
有一起學習的小伙伴可以關注下??我的公眾號——碼上積木,每天三問面試真題,詳細剖析,助你成為offer收割機,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/199390.html
標籤:Android
上一篇:庫克談iPhone 12供應緊張問題;2020中國互聯網百強名單:阿里、騰訊、美團分列前三;Dgraph新版發布|極客頭條
