ViewModel和LiveData問題思考與解答

嗨,你們好,面試真題系列又來了,今天咱們說說MVVM架構裏的兩大組件:ViewModel和LiveData。
仍是老樣子,提出問題,作出解答。java

  • ViewModel 是什麼?面試

  • ViewModel 爲何被設計出來,解決了什麼問題?架構

  • 說說ViewModel原理。app

  • LiveData 是什麼?框架

  • LiveData 爲何被設計出來,解決了什麼問題?ide

  • 說說LiveData原理。post

ViewModel 是什麼,說說你所理解的ViewModel?

若是看過我上一篇文章的小夥伴應該都有所瞭解,ViewModel是MVVM架構的一個層級,用來聯繫View和model之間的關係。而咱們今天要說的就是官方出的一個框架——ViewModel學習

ViewModel 類旨在以注重生命週期的方式存儲和管理界面相關的數據this

官方是這麼介紹的,這裏面有兩個信息:spa

  • 注重生命週期的方式。
    因爲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 = MutableLiveData<String>()

        liveData.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
            }
        })

        liveData.setVaile("xixi")
        //子線程調用
        liveData.postValue("test")

LiveData 爲何被設計出來,解決了什麼問題?

LiveData做爲一種觀察者模式設計思想,經常被和Rxjava一塊兒比較,觀察者模式的最大好處就是事件發射的上游 和 接收事件的下游 互不干涉,大幅下降了互相持有的依賴關係所帶來的強耦合性

其次,LiveData還能無縫銜接到MVVM架構中,主要體如今其能夠感知到Activity等生命週期,這樣就帶來了不少好處:

  • 不會發生內存泄漏
    觀察者會綁定到 Lifecycle 對象,並在其關聯的生命週期遭到銷燬後進行自我清理。

  • 不會因 Activity 中止而致使崩潰
    若是觀察者的生命週期處於非活躍狀態(如返回棧中的 Activity),則它不會接收任何 LiveData 事件。

  • 自動判斷生命週期並回調方法
    若是觀察者的生命週期處於 STARTEDRESUMED狀態,則 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 = 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方法便可。

參考

viewmodel推薦閱讀
livedata推薦閱讀

拜拜

有一塊兒學習的小夥伴能夠關注下❤️個人公衆號——碼上積木,天天三問面試真題,詳細剖析,助你成爲offer收割機。

相關文章
相關標籤/搜索