ViewModel和LiveData問題思考與解答


嗨,大家好,面試真題系列又來了,今天我們說說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 = 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收割機。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM