由于MVP固有的一些因素,比如隨著項(xiàng)目越來越大P層越來越膨脹和內(nèi)存泄露問題,MVVM就面世了。MVVM組成:Model,ViewModel,View,其實(shí)和MVP差不多,就是把Presenter換成了VIewModel。簡單的概括關(guān)系就是:
M --> VM --> V,
M被VM持有,由VM來處理業(yè)務(wù)邏輯,而VM又被V持有,實(shí)際上是形成一條單向線的。不過VM和V會通過binder來實(shí)現(xiàn)雙向綁定,這樣也就進(jìn)一步達(dá)到了解耦的目的。配上一張看到的很形象的圖:

由于谷歌爸爸提供的JetPack庫,我們可以很容易的拿到相應(yīng)的組件來實(shí)現(xiàn)。簡單的提一下相關(guān)的組件:
ViewModel、LiveData/DataBinding、
ViewModel
作為核心成員,實(shí)際上是一個抽象類:

/**
* ViewModel is a class that is responsible for preparing and managing the data for
* an {@link android.app.Activity Activity} or a {@link androidx.fragment.app.Fragment Fragment}.
* It also handles the communication of the Activity / Fragment with the rest of the application
* (e.g. calling the business logic classes).
* <p>
* A ViewModel is always created in association with a scope (an fragment or an activity) and will
* be retained as long as the scope is alive. E.g. if it is an Activity, until it is
* finished.
* <p>
* In other words, this means that a ViewModel will not be destroyed if its owner is destroyed for a
* configuration change (e.g. rotation). The new instance of the owner will just re-connected to the
* existing ViewModel.
* <p>
* The purpose of the ViewModel is to acquire and keep the information that is necessary for an
* Activity or a Fragment. The Activity or the Fragment should be able to observe changes in the
* ViewModel. ViewModels usually expose this information via {@link LiveData} or Android Data
* Binding. You can also use any observability construct from you favorite framework.
* <p>
* ViewModel's only responsibility is to manage the data for the UI. It <b>should never</b> access
* your view hierarchy or hold a reference back to the Activity or the Fragment.
* <p>
* ViewModels can also be used as a communication layer between different Fragments of an Activity.
* Each Fragment can acquire the ViewModel using the same key via their Activity. This allows
* communication between Fragments in a de-coupled fashion such that they never need to talk to
* the other Fragment directly.
* <p>
*/
public abstract class ViewModel {
...
}
經(jīng)典的注解更重要系列,甚至連用法都告訴我們了但太長被我截了(不自覺得跪在了地上)。
注解:
1.ViewModel是一個類,負(fù)責(zé)為Activity或Fragment準(zhǔn)備和管理數(shù)據(jù)。它還處理Activity/Fragment與應(yīng)用程序其余部分的通信(例如,調(diào)用業(yè)務(wù)邏輯類)。
2.ViewModel始終與范圍(片段或活動)相關(guān)聯(lián)地創(chuàng)建,并且只要范圍是活動的,就將被保留。例如。如果是活動,則直到完成。換句話說,這意味著如果ViewModel的所有者因配置更改(例如旋轉(zhuǎn))而被銷毀,則不會銷毀它。所有者的新實(shí)例將重新連接到現(xiàn)有的ViewModel。
3.ViewModel的目的是獲取并保留Activity或Fragment所需的信息。Activity或Fragment應(yīng)該能夠觀察 ViewModel中的更改。 ViewModel通常通過{@link LiveData}或Android Data Binding公開此信息。您也可以使用自己喜歡的框架中的任何可觀察性構(gòu)造。
4.ViewModel的唯一責(zé)任是管理UI的數(shù)據(jù)。它絕不能訪問您的視圖層次結(jié)構(gòu)或保留對活動或片段的引用。
5.ViewModels也可以用作Activity的不同F(xiàn)ragment之間的通信層。每個Fragment都可以通過其Activity使用相同的鍵獲取ViewModel。這允許Fragment之間以解耦的方式進(jìn)行通信,從而使它們無需直接與另一個片段交談。
這樣看來,ViewModel的職責(zé)就很清晰了,就是替Activity或Fragment管理數(shù)據(jù)的,也就是前面說的相當(dāng)于Presenter,用來處理業(yè)務(wù)邏輯,所以本身并沒有很神秘。注意一下第三點(diǎn),View層是應(yīng)該能觀察到ViewModel中的數(shù)據(jù)更改的,可以通過LiveData、DataBinding或者其他的觀察者模式框架來實(shí)現(xiàn),這也就是View和ViewModel實(shí)現(xiàn)雙向綁定的方法。
附一張作用域圖:

簡單使用:
public class UserModel extends ViewModel {
@Override
protected void onCleared() {
super.onCleared();
//do cleared work
}
void doAction(){
// depending on the action, do necessary business logic calls
// and update the userLiveData.
}
}
還是借鑒一下官網(wǎng)的例子:
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<User>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
//這里就可以做一些異步操作來獲取數(shù)據(jù)
}
}
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
就是這么簡單,就把界面和業(yè)務(wù)邏輯分離了,這里用到了LiveData,后面再說。重寫onCleared()做一些資源的釋放,以及我們自己提供一些業(yè)務(wù)邏輯的操作。onCleared()會在Activity/Fragment被回收時調(diào)用,這是怎么做到的呢?
先看下ViewModel是怎么獲取的:
UserModel userModel = new ViewModelProvider(this, new UserModelFactory()).get(UserModel.class);
引入implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'庫則可以使用單參數(shù)構(gòu)造器:
UserModel userModel = new ViewModelProvider(this).get(UserModel.class);
通過ViewModelProvider的get()方法來獲取,先看下這個ViewModelProvider

這里要注意的是androidx.lifecycle:lifecycle-viewmodel:2.2.0包才提供了單參數(shù)的構(gòu)造方法。
get()方法:
@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) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
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);
//noinspection unchecked
return (T) viewModel;
}
可以看到,先根據(jù)類名和DEFAULT_KEY進(jìn)行拼裝得到key,然后在去mViewModelStore里取。如果取出來的viewModel是我們要的類,那就直接返回(此時viewModel可能為null),否則就“l(fā)og a warning”。
接著判斷持有的mFactory是否是KeyedFactory的類型,如果是就通過這個Factory來構(gòu)造出viewModel,如果是別的類型,就直接create。然后把viewModel再放進(jìn)mViewModelStore里,其實(shí)這里也就表明了,如果不同的Activity/Fragment去獲取同類型的ViewModel的話,那么取到的實(shí)例(引用)就是一樣的,那當(dāng)然持有的數(shù)據(jù)就是一致的,也就能達(dá)到通信的效果。
而ViewModelProvider之所以為我們提供了Factory,就是因?yàn)樵讷@取ViewModel的時候我們是不能直接通過new來用構(gòu)造器創(chuàng)建的,這樣的話獲取的都是全新的ViewModel對象,那就沒有意義了。所以由Factory來提供,并可以讓我們創(chuàng)建有參的ViewModel。(這里保留觀點(diǎn),待核實(shí))
看下ViewModelStore:
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();
}
}
很簡單,通過HashMap來存ViewModel,注意一下clear()方法,會將持有的VM都進(jìn)行清理
@MainThread
final void clear() {
mCleared = true;
// Since clear() is final, this method is still called on mock objects
// and in those cases, mBagOfTags is null. It'll always be empty though
// because setTagIfAbsent and getTag are not final so we can skip
// clearing it
if (mBagOfTags != null) {
synchronized (mBagOfTags) {
for (Object value : mBagOfTags.values()) {
// see comment for the similar call in setTagIfAbsent
closeWithRuntimeException(value);
}
}
}
onCleared();
}
可以看到clear()內(nèi)部就調(diào)用了給我們自己實(shí)現(xiàn)的onCleared()方法,到這里我們只知道邏輯,但還是不知道調(diào)用時機(jī)?;剡^頭來看下ViewModelProvider的構(gòu)造函數(shù):
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
提供了兩種構(gòu)造函數(shù),但最終都是通過ViewModelStore和Factory來構(gòu)造的。那這個ViewModelStoreOwner又是什么呢,其實(shí)看名字就應(yīng)該知道,就是用來提供ViewModelStore的。
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
實(shí)際上,就是一個接口??聪滤膶?shí)現(xiàn)類,就是ComponentActivity:
@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.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
重寫了該方法,目的也就是為了提供mViewModelStore。再看下ComponentActivity的繼承關(guān)系:

這樣就很清晰了,也就是說我們的Activity也實(shí)現(xiàn)了ViewModelStoreOwner接口,再看下ComponentActivity的構(gòu)造函數(shù):
public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
//noinspection ConstantConditions
if (lifecycle == null) {
throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
+ "constructor. Please make sure you are lazily constructing your Lifecycle "
+ "in the first call to getLifecycle() rather than relying on field "
+ "initialization.");
}
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();
}
}
}
});
}
這里刪減了其他不相關(guān)的代碼,可以看到,持有了Lifecycle實(shí)例,通過對生命周期的監(jiān)聽(這里是ON_DESTROY),來實(shí)現(xiàn)clear邏輯。這里還要注意的一點(diǎn)是,當(dāng)配置改變的時候(翻轉(zhuǎn)),是不會去清理的。這也很好理解,因?yàn)橹皇墙缑嬷乩L,數(shù)據(jù)如果重新獲?。╒iewModel)那還是一樣的數(shù)據(jù)。
到這里,為什么ViewModel能在Activity被回收時去清理資源就很清晰了。
LiveData
上面也有提到,其實(shí)真正存儲數(shù)據(jù)的是LiveData。先從用法入手:
userModel.liveData.observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
textView.setText(String.valueOf(integer));
}
});
LiveData由ViewModel來持有,為其添加觀察者并指定動作則可以監(jiān)聽數(shù)據(jù),當(dāng)數(shù)據(jù)變化時我們就可以更新UI或者做其他的事情,經(jīng)典的觀察者模式。
public abstract class LiveData<T> {
@SuppressWarnings("WeakerAccess") /* synthetic access */
final Object mDataLock = new Object();
static final int START_VERSION = -1;
@SuppressWarnings("WeakerAccess") /* synthetic access */
static final Object NOT_SET = new Object();
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
// how many observers are in active state
@SuppressWarnings("WeakerAccess") /* synthetic access */
int mActiveCount = 0;
private volatile Object mData;
// when setData is called, we set the pending data and actual data swap happens on the main
// thread
@SuppressWarnings("WeakerAccess") /* synthetic access */
volatile Object mPendingData = NOT_SET;
private int mVersion;
private boolean mDispatchingValue;
@SuppressWarnings("FieldCanBeLocal")
private boolean mDispatchInvalidated;
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
/**
* Creates a LiveData initialized with the given {@code value}.
*
* @param value initial value
*/
public LiveData(T value) {
mData = value;
mVersion = START_VERSION + 1;
}
/**
* Creates a LiveData with no value assigned to it.
*/
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
}
注釋比較長就沒貼了,大致如下:
1.LiveData是可以在給定生命周期內(nèi)觀察到的數(shù)據(jù)持有者類。這意味著可以將{@link Observer}與{@link LifecycleOwner}成對添加,并且只有配對的LifecycleOwner處于活動狀態(tài)時,才會向該觀察者通知有關(guān)包裝數(shù)據(jù)的修改。如果LifecycleOwner的狀態(tài)為{@link Lifecycle.StateSTARTED}或{@link Lifecycle.StateRESUMED},則將其視為活動狀態(tài)。通過{@link watchForever(Observer)}添加的觀察者被視為始終處于活動狀態(tài),因此將始終收到有關(guān)修改的通知。對于這些觀察者,您應(yīng)該手動調(diào)用{@link removeObserver(Observer)}。
2.如果相應(yīng)的生命周期變?yōu)閧@link Lifecycle.StateDESTROYED}狀態(tài),則添加了生命周期的觀察者將被自動刪除。這對于活動和片段可以安全地觀察LiveData而不用擔(dān)心泄漏的活動特別有用:銷毀它們時,它們將立即被取消訂閱。
3.此外,LiveData具有{@link LiveData#onActive()}和{@link LiveData#onInactive()}方法,可在活動{@link Observer}的數(shù)量在0到1之間變化時得到通知。這就允許LiveData可以釋放大量的資源,當(dāng)沒有任何正在觀察的觀察者時。
4.此類旨在容納{@link ViewModel}的各個數(shù)據(jù)字段,但也可以用于以解耦的方式在應(yīng)用程序中的不同模塊之間共享數(shù)據(jù)。
幾個重要的字段:
mDataLock:設(shè)值時的鎖
START_VERSION:數(shù)據(jù)(消息)起始版本
mObservers:觀察者集合SafeIterableMap,其實(shí)是由雙向鏈表來偽裝成的Map
mData:持有的數(shù)據(jù)
mVersion:當(dāng)前數(shù)據(jù)版本
mPostValueRunnable:提供設(shè)值邏輯
有兩個構(gòu)造函數(shù),帶值的就直接將值賦給mData,并將起始版本號加1(因?yàn)橐呀?jīng)有數(shù)據(jù)了嘛);無參構(gòu)造函數(shù)就正常初始化。
我們就先從observe()方法看起,這也是第一條注釋提到的,可以將Observer(觀察者)和LifecycleOwner(生命周期持有者)成對添加。
/**
* @param owner The LifecycleOwner which controls the observer
* @param observer The observer that will receive the events
*/
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
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);
}
從名字也可以看出,這個方法就是用來添加(注冊)觀察者的,而LifecycleOwner則是對應(yīng)的觀察者的生命周期持有者,是一個有關(guān)生命周期的接口,由ComponentActivity實(shí)現(xiàn)。目的很簡單,匿名內(nèi)部類持有外部類引發(fā)的內(nèi)存泄漏,以及當(dāng)我們頁面都已經(jīng)關(guān)閉了,那么再來接收事件(更新界面)那就沒有意義了。
首先assertMainThread()方法就是來判斷當(dāng)前是否為主線程,如果不是就拋出異常(這里因該是持有了LifecycleOwner的原因)。接著判斷當(dāng)前LifecycleOwner的狀態(tài),如果是DESTROYED狀態(tài)就直接return掉。
緊接著封裝了一個LifecycleBoundObserver對象,主要提供了解綁Observer方法,然后添加到mObservers中。如果觀察者已經(jīng)存在并且綁定到了owner,那就拋出異常。
最后拿到Lifecycle(抽象類,實(shí)現(xiàn)類為LifecycleRegistry)對象,調(diào)用addObserver()添加wrapper,這里主要就是監(jiān)聽生命周期狀態(tài)。
還提供了observeForever(),也就是無論生命周期狀態(tài)如何都一直監(jiān)聽,那就需要我們自己去移除監(jiān)聽者,這里就不看了。
接著看下setValue()方法:
/**
* Sets the value. If there are active observers, the value will be dispatched to them.
* <p>
* This method must be called from the main thread. If you need set a value from a background
* thread, you can use {@link #postValue(Object)}
*
* @param value The new value
*/
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
設(shè)置值,如果有存活的observer就去分發(fā)。一樣先判斷是否是主線程,將mVersion加1(相當(dāng)于這是新版本的數(shù)據(jù)),將新值賦給mData,進(jìn)行分發(fā):
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
在setValue()方法中調(diào)用dispatchingValue()時傳入了null,所以先看initiator為null的情況。很簡單,就是拿到mObservers的迭代器,然后調(diào)用considerNotify()方法判斷這個Observer是否要通知,看下considerNotify()方法:
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;
observer.mObserver.onChanged((T) mData);
}
首先還是先判斷了observer是否是Active狀態(tài),如果不是就調(diào)用observer.activeStateChanged(false)去更新狀態(tài);
接著判斷observer的mLastVersion是否大于或等于LiveData的mVersion,如果是就直接return。也就是說,數(shù)據(jù)(消息)的版本(mVersion)要大于監(jiān)聽者的版本(mLastVersion )時,才會去做數(shù)據(jù)的分發(fā)通知,我們只對新版本的數(shù)據(jù)感興趣(也可以把mVersion當(dāng)做最新的消息版本,把mLastVersion當(dāng)做上一次的消息版本,只有新消息的版本大于上一次消息的版本,我們才去通知)。其實(shí)這里也是引發(fā)粘性事件的地方,EventBus也是。往回看就可以知道,不管是observer.mLastVersion還是mVersion,它們的起始值都是START_VERSION(-1),而在setValue()的時候,mVersion進(jìn)行了自加,也就是第一次的時候就變?yōu)榱?,而mLastVersion并沒有改動。那么這就導(dǎo)致了,即使是后于設(shè)值注冊的observer,走到這里的時候,mLastVersion(-1)是小于mVersion(0)的,這也就讓數(shù)據(jù)正常的往下走通知了出去。這也是為什么我們在使用EventBus去發(fā)消息的時候,明明消息已經(jīng)發(fā)出去了,而新開啟的Activity注冊之后仍然能接收到的原因。當(dāng)然這點(diǎn)也可以利用來作為Activity間開啟的數(shù)據(jù)傳遞。
接著就是將mVersion賦給mLastVersion,告訴observer:這個數(shù)據(jù)已經(jīng)舊了,下次要獲取就要獲取新的。然后回調(diào)observer的onChanged()方法把數(shù)據(jù)更新出去,這也就是一開始調(diào)用observe()來添加observer需要重寫的方法。
后記
不知不覺,這篇文章居然在草稿箱里躺了至少快兩年,當(dāng)初是想說感覺寫的還不夠成熟想在完善一下再發(fā),沒想到一擱置就這么久...懶真的是要命啊啊啊ε=ε=ε=(#>д<)?