嗨,你們好,面試真題系列又來了,今天咱們說說MVVM架構裏的兩大組件:ViewModel和LiveData。
仍是老樣子,提出問題,作出解答。java
ViewModel 是什麼?面試
ViewModel 爲何被設計出來,解決了什麼問題?架構
說說ViewModel原理。app
LiveData 是什麼?框架
LiveData 爲何被設計出來,解決了什麼問題?ide
說說LiveData原理。post
若是看過我上一篇文章的小夥伴應該都有所瞭解,ViewModel
是MVVM架構的一個層級,用來聯繫View和model之間的關係。而咱們今天要說的就是官方出的一個框架——ViewModel。學習
ViewModel 類旨在以注重生命週期的方式存儲和管理界面相關的數據this
官方是這麼介紹的,這裏面有兩個信息:spa
ViewModel
的生命週期是做用於整個Activity的,因此就節省了一些關於狀態維護的工做,最明顯的就是對於屏幕旋轉這種狀況,之前對數據進行保存讀取,而ViewModel
則不須要,他能夠自動保留數據。其次,因爲ViewModel
在生命週期內會保持局部單例,因此能夠更方便Activity的多個Fragment
之間通訊,由於他們能獲取到同一個ViewModel實例,也就是數據狀態能夠共享了。
ViewModel
層的根本職責,就是負責維護界面上UI的狀態,其實就是維護對應的數據,由於數據會最終體現到UI界面上。因此ViewModel
層其實就是對界面相關的數據進行管理,存儲等操做。
ViewModel
組件被設計出來以前,MVVM又是怎麼實現ViewModel這一層級的呢?其實就是本身編寫類,而後經過接口,內部依賴實現View和數據的雙向綁定。
因此Google出這個ViewModel組件,無非就是爲了規範MVVM
架構的實現,並儘可能讓ViewModel這一層級只觸及到業務代碼,不去關心VIew層級的引用等。而後配合其餘的組件,包括livedata,databindingrang
等讓MVVM架構更加完善,規範,健碩。
其實上面已經說過一些了,好比:
1)不會由於屏幕旋轉而銷燬,減小了維護狀態的工做
2)因爲在做用域內單一實例的特性,使得多個fragment
之間能夠方便通訊,而且維護同一個數據狀態。
3)完善了MVVM
架構,使得解耦更加純粹。
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 具備生命週期感知能力,意指它遵循其餘應用組件(如 Activity、Fragment 或 Service)的生命週期。這種感知能力可確保 LiveData 僅更新處於活躍生命週期狀態的應用組件觀察者。
官方介紹以下,其實說的比較清楚了,主要做用在兩點:
數據存儲器類
。也就是一個用來存儲數據的類。
可觀察
。這個數據存儲類是能夠觀察的,也就是比通常的數據存儲類多了這麼一個功能,對於數據的變更能進行響應。
主要思想就是用到了觀察者模式
思想,讓觀察者和被觀察者解耦,同時還能感知到數據的變化,因此通常被用到ViewModel中,ViewModel
負責觸發數據的更新,更新會通知到LiveData
,而後LiveData再通知活躍狀態的觀察者。
var liveData = MutableLiveData<String>() liveData.observe(this, object : Observer<String> { override fun onChanged(t: String?) { } }) liveData.setVaile("xixi") //子線程調用 liveData.postValue("test")
LiveData
做爲一種觀察者模式設計思想,經常被和Rxjava
一塊兒比較,觀察者模式的最大好處就是事件發射的上游 和 接收事件的下游 互不干涉,大幅下降了互相持有的依賴關係所帶來的強耦合性
。
其次,LiveData還能無縫銜接到MVVM
架構中,主要體如今其能夠感知到Activity
等生命週期,這樣就帶來了不少好處:
不會發生內存泄漏
觀察者會綁定到 Lifecycle
對象,並在其關聯的生命週期遭到銷燬後進行自我清理。
不會因 Activity 中止而致使崩潰
若是觀察者的生命週期處於非活躍狀態
(如返回棧中的 Activity),則它不會接收任何 LiveData 事件。
自動判斷生命週期並回調方法
若是觀察者的生命週期處於 STARTED
或 RESUMED
狀態,則 LiveData 會認爲該觀察者處於活躍狀態,就會調用onActive
方法,不然,若是 LiveData 對象沒有任何活躍觀察者時,會調用 onInactive()
方法。
說到原理,其實就是兩個方法:
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 = value; dispatchingValue(null); } private void dispatchingValue(@Nullable ObserverWrapper initiator) { //... do { mDispatchInvalidated = false; if (initiator != null) { considerNotify(initiator); initiator = null; } else { for (Iterator<Map.Entry<Observer<T>, 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
方法便可。
有一塊兒學習的小夥伴能夠關注下❤️個人公衆號——碼上積木,天天三問面試真題,詳細剖析,助你成爲offer收割機。