基於 Android Architecture Components 的 MVVM 淺析

0、前言

官方文檔永遠是最好的學習資料:
Android Jectpack
Android Jetpack: LiveData 和 Lifecycle 介紹 | 中文教學視頻
Android Jetpack - ViewModel | 中文教學視頻
Android Jetpack Room | 中文教學視頻
深刻了解還需多看文檔和源碼。java

一、簡介

1.一、AAC 是什麼

AAC (Android Architecture Components) 是谷歌推出的一套包含在 Jetpack 中的,幫助咱們構建穩健、可測試且易維護應用的組件庫,主要包括 LifecycleLiveDataViewModelRoomWorkManager 等一系列好用的工具。注意,AAC 並非一種新的架構,只是一套和架構相關的工具,能夠幫助你更加簡單高效的構建你想要的架構。android

1.二、AAC 與 MVVM

MVC (Model-View-Controller)、MVP (Model-View-Presenter) 和 MVVM (Model-View-ViewModel) 在 Android 中的應用大概能夠歸納爲下圖(架構分層因人而異,這裏只是我本身的一些理解)
git


在 MVP 的架構中,View 層和 Presenter 層相互引用對方,Presenter 層收到 View 層的動做或者拿到 Model 層的數據後主動調用 View 的一些方法,顯示相應的結果。Presenter 層就像個全職保姆同樣,上有 View 層要處理動做和顯示,下有 Model 層要請求和處理數據,中間本身還要處理業務邏輯。咱們通常須要定義 IViewIPresenter 之類的接口,而後 View 層和 Presenter 層相互持有對方的引用,這樣就存在不少問題,好比:

  • View 和 Presenter 解耦不完全,Presenter 須要具體知道 View 層的能力
  • 由於 View 層和 Model 層之間的通信和其餘業務層面的大小事務都由它來處理,會致使 Presenter 過分膨脹
  • View 層的生命週期和 Presenter 層不一致,以及內存泄漏等問題
    注意 弱引用只能解決內存泄露的問題,沒法解決生命週期的問題,好比 Activity 已經 onDestroy,但並無被回收的場景
  • 擴展性差,增刪 View 層或變動業務要改動不少代碼

MVVM 採用 View 層與 ViewModel 層的數據綁定的方式,View 層監聽相應的數據,並在數據變動時本身更改視圖,從而很好地解決了上述問題:github

  • View 層和 ViewModel 層鬆耦合,ViewModel 層不須要持有具體的 View,也不須要知道 View 層的任何東西
  • ViewModel 層很輕,ViewModel 層只須要把新的數據通知到各個 View,而不關心 View 的顯示
  • 因爲 ViewModel 層不直接引用 View 層,生命週期更好處理
  • ViewModel 層不關心 View 層的變動,不也不關心 View 的數量,甚至不關心監聽的是否是 View

可見 MVVM 更爲先進好用,實現 MVVM 的方法也有不少,而 AAC 就是爲 MVVM 而生的,經過 AAC 中的 LiveDataViewModel 等組件,咱們能夠很容易地在 Android 上實現 MVVM。它的 Lifecycle 組件可讓咱們更有效的管理 app 內的各類生命週期,在配置變動時保存數據,避免內存泄漏,更方便地把數據加載到 UI 中;LiveData 用來構建一個能夠在數據變動時通知視圖的數據對象,且具備生命週期感知的能力;ViewModel 能夠存儲 UI 相關的數據,並保證在配置變動時不會丟失。數據庫

二、基於 AAC 的 MVVM 簡單用法

2.一、LiveData

LiveData 是一個可觀察的數據持有類,並且它能夠感知其餘應用組件 (如 ActivityFragmentService) 的生命週期,這種感知可確保 LiveData 僅更新生命週期處於激活狀態(STARTED 和 RESUMED)的觀察者。它的主要優勢有:緩存

  • UI 與數據同步,利用觀察者模式,能夠在數據變化時通知 UI
  • 不存在內存泄露,會在觀察者對應的生命週期結束後自動移除觀察者
  • 不會更新非激活狀態(STOPPED)狀態的 UI,以避免形成崩潰(Fragment Transaction)
  • 不須要手動處理生命週期事件
  • UI 從非激活狀態切換到激活狀態時,會收到 LiveData 的最新數據,數據預加載再也不須要考慮 View 的狀態
  • ActivityFragment 重建時也會收到通知(須要和 ViewModel 配合使用)

簡單用法。假設咱們的 MainActivity 的視圖中有一個 Button 和一個 TextView 來實現一個簡單的計數器,還有一個計數值的 LiveData。點擊 Button 會更新計數值,而 TextView 監聽該 LiveData 來更新本身。示例分析以下:網絡

public class MainActivity extends AppCompatActivity {
    // 一、MutableLiveData 是什麼
    private MutableLiveData<Integer> mLiveData = new MutableLiveData<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 初始化工做
        // ...
        
        mLiveData.setValue(0);
        
        // 二、LiveData.observe() 的參數都是什麼意思
        // public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
        mLiveData.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable final Integer count) {
                // Update the UI, in this case, a TextView.
                mTextView.setText(newName);
            }
        });
        
        // 三、LiveData 的值怎麼更新
        mButton.setOnClickListener(v -> mLiveData.setValue(mLiveData.getValue() + 1));
    }
}
複製代碼

一、首先 LiveData 是一個抽象類,且 setValuepostValue 兩個更新 value 的方法都是 protected 的,而 MutableLiveData 繼承 LiveData,重寫這兩個方法,並將訪問權限設置爲 public架構

二、public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
第一個參數 LifecycleOwner 是持有生命週期的對象,好比 ActivityFragment,可讓 LiveData 能夠感知它的生命週期,並在生命週期結束時將其移除,避免內存泄漏;第二個參數 Observer 是一個接口,它只有一個方法 void onChanged(T t)LiveData 會在數據更新時調用這個函數來通知 UI 層的觀察者。併發

三、setValuepostValue 兩個均可以更新 value,不一樣之處在於 setValue 只能在主線程調用,而 postValue 能夠用於子線程(注意:短期內屢次 postValueLiveData 只會保留最後一個來通知觀察者)。app

固然,這只是LiveData 用法的簡單說明,實際項目中若是這樣用會有些問題:

  • 把數據相關的東西放在了 View 層,固然咱們能夠單獨抽一層放 LiveData 來解決這個問題
  • 在配置變動(如屏幕旋轉)時,ActivityFragment 會重建致使數據丟失,這個問題固然能夠經過 onSaveInstanceState 來保留和恢復數據;
  • 若是多個 View 都須要一樣的數據源或者相互通信,難以保證拿到同一個 LiveData,單例能夠解決這個問題,但數據源不在被須要時也沒法回收資源。

上面說的這些問題均可以經過某些手段解決,可是都不是很優雅,而谷歌固然考慮到了,這些問題在接下來的 ViewModel 中,都獲得了很好的解決。

2.二、ViewModel

ViewModel,顧名思義,是用來存儲和管理 View 相關數據的,而 AAC 中的 ViewModel 還能夠感知生命週期,能夠在配置變動(如屏幕旋轉)時自動保存數據,還能夠在生命週期真的結束時觸發回調來清除沒必要要的請求,以避免內存泄漏。而做爲 MVVM 的中間層,它還肩負着響應 View 層的動做,以及操做 Model 層請求數據的任務。ViewModel 的生命週期以下圖所示:


注意ViewModel 因爲生命週期是長於 View 層( ActivityFragmentView)的,不能(也不須要)持有 View 層的任何東西,若是要使用 context 能夠繼承 AndroidViewModel,它內部持有 Application 的 context。
簡單用法。

public class MyViewModel extends ViewModel {
    // ...
    
    public List<User> getUsers() {
        return users;
    }

    public void loadUsers() {
        // 請求 users 數據.
    }
    
    // 一、調用時機
    @Override
    protected void onCleared() {
        // 清除沒必要要的請求 
    }
}

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // MyActivity 重建時仍是能拿到同一個 MyViewModel
        // 二、ViewModelProviders.of 參數
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.loadUsers();
    }
}
複製代碼

一、ViewModelonCleared 函數會在持有它的對象的生命週期結束時調用,以避免異步請求形成 ViewModel 的內存泄露;

二、public static ViewModelProvider of(@NonNull FragmentActivity activity)public static ViewModelProvider of(@NonNull Fragment fragment),傳入的參數能夠是 ActivityFragment,其內部會拿到 ActivityFragmentViewModelStore,顧名思義就是存儲 ViewModel 的地方,其內部也只是一個 HashMap<String, ViewModel>,鍵是內部用 ViewModelClass 的名字拼出的字符串。

利用 ViewModelStore 存儲 ViewModel 能夠十分方便地管理 ViewModel ,前面說的 ViewModel 能夠在配置變動後存活,其實就是在重建保存狀態時,保存下了 ViewModelStore,實現方式和保存 Fragment 相似(Bundle 保存的數據是有限的,爲了在配置變動時保存大量數據,也能夠用 Fragment 來存)。利用 ViewModelStore 存儲 ViewModel 的方式還能夠方便 Fragment 之間的通信和數據同步,只要多個 Fragment 隸屬於 同一個 Activity,他們就能夠經過 ActivityViewModelStore 拿到同一個 ViewModel

2.三、MVVM

雖然 LiveDataViewModel 單獨拿出來用也是強有力的工具,谷歌推出 AAC 的目的明顯不只僅是一個工具,這一整套服務於的架構相關的組件能夠幫助咱們輕鬆的打造 MVVM,並且都帶着生命週期感知能力。接下來經過一個計數器例子,簡單介紹下使用方法。

public class CountViewModel extends ViewModel {
    private final MutableLiveData<Integer> mCountLiveData = new MutableLiveData<Integer>();
    
    public LiveData<Integer> getCountLiveData() { return mCountLiveData; }

    public void loadCount() {
        // 能夠經過網絡或數據庫請求數據
        request.enquen(response -> { 
            if (response.isSuccess()) {
                mCountLiveData.postValue(response.data);
            }
        });
    }
    
    public void countDown() {
        // 減少計數
        if (mCountLiveData.getValue() != null) {
            mCountLiveData.setValue(mCountLiveData.getValue() - 1);
        } else {
            loadCount();
        }
    }
    
    public void countUp() {
        // 增大計數
        if (mCountLiveData.getValue() != null) {
            mCountLiveData.setValue(mCountLiveData.getValue() + 1);
        } else {
            loadCount();
        }
    }
}

public class ActionFragment extends Fragment {
    //...
    
    @Override
    public void onViewCreated(View v, Bundle savedInstanceState) {
        final CountViewModel countViewModel =  ViewModelProviders.of(getActivity()).get(MyViewModel.class);
        // 改變計數值
        v.findViewById(R.id.up_buttonn).setOnClickListener(v -> {
            countViewModel.countUp();
        });
        v.findViewById(R.id.down_buttonn).setOnClickListener(v -> {
            countViewModel.countDown();
        });
    }
    
    //...
}

public class ShowCountFragment extends Fragment {
    //...
    
    @Override
    public void onViewCreated(View v, Bundle savedInstanceState) {
        final TextView count = v.findViewById(R.id.count_text_view);
        // 這裏的 getActivity() 是爲了拿到同一個 CountViewModel
        ViewModelProviders.of(getActivity())
            .get(CountViewModel.class)
            .getCountLiveData()
            // 這裏的 this 是爲了讓 LiveData 綁定觀察者的生命週期
            .observe(this, data -> {
                count.setText(data);
            });
    }
    
    //...
}
複製代碼

在該例子中,CountViewModel 中有一個 mCountLiveData 用於保存計數值,還有一組用於更新計數值的方法;ActionFragmentShowCountFragment 位於同一個 Activity 中,這樣能夠保證二者拿到同一個 CountViewModelActionFragment 的兩個按鈕用於增減計數,而 ShowCountFragment 則監聽並顯示計數值。

這樣一個簡單的 MVVM 架構的計數器就搭建好了。View 層的 ShowCountFragment 綁定 ViewModel 層的 mCountLiveData,並在數據變動時更新視圖,而 ViewModel 層不須要直接持有任何 View 層的引用(LiveData 持有的觀察者在 View 層,可是會自動根據生命週期來移除),ViewModel 也不關心監聽數據的 View 的數量和類型,View 拿到數據後顯示什麼東西也都無所謂,多一個 View 只不過是多了一個觀察者而已,並且多個 View 不須要藉助其餘工具(EventBus、RxBus 等事件總線)就能夠經過 ViewModel 實現通訊。

對於數據源比較多的場景,谷歌建議咱們單獨抽出 Repository 層(其實就是 Model 層)用於處理數據來源(緩存、數據庫或網絡),並向上返回數據的 LiveData(如 Room)來保持數據的同步,整個架構圖以下圖所示:

MVVM

三、進一步瞭解 AAC

**配合源碼使用,效果更佳!**特別推薦使用 androidx 來看源碼,會清晰方便不少。

3.一、Lifecycle

View 層的動態性很強,各個界面切換、視圖元素交替出現等都伴隨着生命週期的變化,而下層元素的生命週期每每要長於 View 的生命週期,爲了避免形成資源浪費和內存泄漏,咱們時常須要手動管理 View 的生命週期。好比咱們有一個顯示當前位置的 Activity,咱們須要在 onStart 時開始監聽位置信息,並在位置變化時更改視圖,在 onStop 時註銷監聽。


手動管理 ActivityFragment 的生命週期是一件十分繁瑣並且低效的事情,爲了更有效地管理生命週期,許多第三方庫(例如 Glide、RxLifecycle)都將監聽與分發生命週期地任務交給 Frgament,由於只要將 Frgament 塞進 Activity 中, Frgament 就能與 Activity 生命週期同步,而後經過自定義的 Frgament 將生命週期事件發送出來。AAC 中的 Lifecycle 組件也是經過這種方式和觀察者模式實現了生命週期地自動管理。

Lifecycle 組件主要有 LifecycleLifecycleObserver 和一套相關地類組成。Lifecycle 定義了一系列生命週期地狀態和事件,其惟一子類 LifecycleRegistry 則實現了一個做爲生命週期被觀察者所具備的能力,在生命週期變化時向觀察者們分發事件。LifecycleObserver 是一個起標識做用地接口,它的子接口 LifecycleEventObserveronStateChanged 方法在 LifecycleRegistry 分發生命週期時會被回調。

如今問題來了:

  • 咱們怎麼拿到 Lifecycle

Lifecycle 的持有者都會實現 LifecycleOwner 接口,重寫 Lifecycle getLifecycle();方法,返回本身持有的生命週期對象 LifecycleRegistryActivityFragment 都實現了該接口。

  • Lifecycle 的生命週期事件從哪裏來,和以前說的 Frgament 有什麼關係?

LifecycleOwner 的實現類既然持有 Lifecycle,那確定就會發送事件啦。Frgament 的話比較簡單,內部保存了一個 mLifecycleRegistry,並在本身的生命週期事件中調用 mLifecycleRegistryhandleLifecycleEvent 方法將事件傳遞給 LifecycleRegistryActivity 本身也持有一個 mLifecycleRegistry,可是它不本身發送事件,而是把任務交給了一個叫 ReportFragmentFragment,其實現也很簡單,就是在本身的生命週期事件中拿到 ActivitymLifecycleRegistry,而後再進行分發。

  • LifecycleObserver 怎麼用

須要監聽 Lifecycle 的對象實現這個接口,而後在 onStateChanged 方法中根據不一樣的生命週期作出相應的動做。好比前面說的監聽位置信息的例子,咱們就能夠單獨抽出一個對象來專門作監聽操做,實現 LifecycleObserver 接口,並本身處理生命週期事件。

class MyLocationListener implements LifecycleObserver {
    private boolean enabled = false;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
       //...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void start() {
        if (enabled) {
           // connect
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop() {
        // disconnect if connected
    }
}
複製代碼

3.二、ViewModel

這裏咱們來扒一扒源碼,看 ViewModel 是如何建立、如何挺過配置變動,又是什麼時候真正的消失的。

  • ViewModel 的建立

前面咱們已經知道 ViewModel 都保存在 ViewModelStore 中,那隻要知道 ViewModelStore 如何被建立、保存與銷燬就行。在 ComponentActivitygetViewModelStore 方法能夠看到 ViewModelStore 的建立過程。

if (mViewModelStore == null) {
    NonConfigurationInstances nc =
            (NonConfigurationInstances) getLastNonConfigurationInstance();
    if (nc != null) {
        // Restore the ViewModelStore from NonConfigurationInstances
        mViewModelStore = nc.viewModelStore;
    }
    if (mViewModelStore == null) {
        mViewModelStore = new ViewModelStore();
    }
}
複製代碼

能夠看到 ViewModelStore 是從一個叫 NonConfigurationInstances 的實例中拿的,若是拿不到說明以前沒經歷過配置變動,那就 new 一個出來。接着看

// ComponentActivity 裏的
static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}
複製代碼

NonConfigurationInstances 除了保存 ViewModelStore 還存着 custom 用於保存咱們本身定製的數據,這個能夠經過重寫 onRetainCustomNonConfigurationInstance 方法來用。再來看下 getLastNonConfigurationInstance

public Object getLastNonConfigurationInstance() {
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}
// 這個是 Activity 中的,和 ComponentActivity 裏的那個不同
static final class NonConfigurationInstances {
    Object activity;
    HashMap<String, Object> children;
    FragmentManagerNonConfig fragments;
    ArrayMap<String, LoaderManager> loaders;
    VoiceInteractor voiceInteractor;
}
複製代碼

是在 ActivityNonConfigurationInstances 中的 activity,經過 NonConfigurationInstances 咱們也能大體看出 Fragment 在配置變動的時候會被保存到 FragmentManagerNonConfig 中。

  • 接下來看如何挺過配置變動的

ComponentActivityonRetainNonConfigurationInstance 中會分別拿咱們定製的 customViewModelStore,而後返回建立好的 NonConfigurationInstances。而 onRetainNonConfigurationInstance 會在配置變動時被 LocalActivityManagerdispatchRetainNonConfigurationInstance 方法中調用,從而保存狀態信息。至此咱們就知道保存 ViewModelStore 的流程,再繼續深刻源碼就沒法自拔了。

  • 最後看下何時真正的銷燬 ViewModel,調用它的 onCleared
getLifecycle().addObserver(new GenericLifecycleObserver() {
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            if (!isChangingConfigurations()) {
                getViewModelStore().clear();
            }
        }
    }
});
複製代碼

ComponentActivity 的構造函數中有這麼一段代碼,恰好用到了咱們前面說的 LifecycleLifecycleObserver,在 ON_DESTROY 時判斷下是不是配置變動,不是的話就調用 ViewModelStoreclear 方法,會清除 ViewModelStore 中保存的 ViewModel,並調用他們的 clear 方法,進而調用到 onCleared

至此,Activiy 中的 ViewModel 相關生命週期已經分析完了,Fragment 中也大同小異,主要涉及 FragmentManagerImplFragmentManagerViewModel 等一些類,感興趣的能夠順着 ViewModelStore 的思路,本身深刻了解下。

3.三、LiveData 擴展用法

觀察者模式的那套東西均可以玩一些騷操做,責任鏈、事件總線什麼的,LiveData 做爲一個可觀察對象,固然也能夠,這裏簡單分析兩個。

首先了解下一個叫 MediatorLiveData 的對象,它繼承自 MutableLiveData,經過 public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) 方法實現了增長其餘 LiveData 做爲本身事件源的功能,源 LiveData 更新時,會調用傳入的 ObserveronChanged 方法作處理。MediatorLiveData 是利用 public void observeForever(@NonNull Observer<? super T> observer) 方法來添加源的,這個方法不須要傳 LifecycleOwner,可是須要手動移除觀察者,不過不用擔憂,MediatorLiveData 已經幫咱們作了。若是 MediatorLiveData 已經沒有任何觀察者,它會自動調用源 LiveDataremoveObserver 方法來移除對源 LiveData 的監聽,以防本身內存泄漏。

利用 MediatorLiveData 對象,咱們能夠作一些事件變換的操做,TransformationsmapswitchMap 就是經過該對象實現的。

以前的事件總線都須要手動處理生命週期的問題,EventBus 須要手動註銷,RxBus 須要 RxLifecycle 的擴展庫來監聽生命週期。有了 LiveData,咱們徹底能夠用不多的代碼擼一個具備生命週期感知能力的事件總線,實現很簡單(一個簡單但實用的 LiveDataBus 只須要一百行代碼左右),網上也有不少開源的庫,這裏只講下大體思路。

要想作事件總線,核心就是發送方和接收方拿到同一個可觀察對象,在這裏就是同一個 LiveData。最簡單的方法就是定義一個單例類,假設叫 LiveDataBus,裏面放一個 Map<Class<?>, MutableLiveData<?>> 來保存全部的事件類型 Class 和對應的 LiveData,這樣就能經過事件的 Class 拿到對應的惟一 LiveData。這裏有幾個須要注意的地方:

  • Map 的併發問題,由於來拿 LiveData 的可能多個線程的,因此要作好同步工做,再考慮到可見性,建議用 ConcurrentHashMap
  • Map 裏存的 ClassMutableLiveData 都被擦出了泛型(不一樣事件的 Class<T> 裏泛型確定不同呀),因此要本身保證二者的泛型一致,能夠定義一個保存 Class<T>MutableLiveData<T> 的帶泛型 <T> 的類,在裏面保證一致;
  • LiveDataBus 中的 LiveData 不會被釋放,也就致使它裏面的數據不會被釋放,能夠在事件不用時發送一個空事件;
  • 全局的事件總線會形成業務間的耦合,並且很差調試,除非關鍵事件,不要濫用。

注意ViewModel 已經可以解決不少場合的通訊問題,並且能在不用時釋放掉,因此能用 ViewModel 通訊的就不要用事件總線,除非兩個 Activity 必須經過某種方式進行通信,也要先考慮下單例的 LiveData,實在不行再用事件總線。

最後再強調一遍,不要濫用事件總線

3.四、LiveData 源碼分析

LiveData 源碼很少,這裏只簡單分析幾個 LiveData 的特性。

  • 如何在觀察者生命週期結束自動移除觀察者

LiveData 的訂閱方法看起

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    // ...
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    // ...
    owner.getLifecycle().addObserver(wrapper);
}
複製代碼

能夠看到 LiveData 不只是一個可觀察對象,同時仍是一位觀察者,它所觀察的就是 ActivityFragment 等持有 LifecycleLifecycleOwner,固然也要把觀察本身的觀察者保存下來,接下來看下 LifecycleBoundObserver 這個觀察者是怎麼處理 Lifecycle 的。首先它繼承自 ObserverWrapper 這是一個會根據 Lifecycle 是否處於激活狀態決定是否分發數據的觀察者,這裏先跳過,LifecycleBoundObserver 還實現了 GenericLifecycleObserver 接口,其實就是前面說過的 LifecycleEventObserver,它的生命週期狀態回調函數以下:

// LifecycleBoundObserver 的方法
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

// LiveData 的方法
public void removeObserver(@NonNull final Observer<? super T> observer) {
    // ...
    ObserverWrapper removed = mObservers.remove(observer);
    // ...
    removed.detachObserver();
    removed.activeStateChanged(false);
}

// LifecycleBoundObserver 的方法
void detachObserver() {
    mOwner.getLifecycle().removeObserver(this);
}
複製代碼

onStateChanged 在判斷 Lifecycle DESTROYED 的時候調用 LiveDataremoveObserver,首先將觀察 LiveData 的觀察者移除,防止內存泄漏,以後再調用LifecycleBoundObserverdetachObserver 將本身從 LifecycleOwner 的觀察者中移除,自此將相互之間的觀察狀態接觸。

  • 觀察者的生命週期從非激活態到激活態時是怎麼收到通知的

作預加載的時候,咱們能夠在 ActivityFragment 建立時直接請求數據,塞到 LiveData,而後只要生命週期處於激活狀態,無論何時監聽 LiveData,都能收到最新的消息。咱們再來看一下 LifecycleBoundObserveronStateChanged 方法,它在最後調用了父類的 activeStateChanged(shouldBeActive()) 方法,來大體看一下

void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    // immediately set active state, so we'd never dispatch anything to inactive
    // owner
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) {
        // 該方法是 LiveData 的
        onActive();
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) {
        // 該方法是 LiveData 的
        onInactive();
    }
    if (mActive) {
        dispatchingValue(this);
    }
}
複製代碼

它首先會根據當前的激活狀態進行去重,而後會根據 LiveData 的觀察者處於激活狀態的數量和新的狀態判斷是否調用 onActiveonInactive,這兩個也是 LiveData 的重要回調,不過都好理解,就不在細說了。最後會判斷如今是不是激活狀態,是的話就調用 LiveDatadispatchingValue 方法,顧名思義就是 LiveData 向其觀察者發送通知。而 dispatchingValue 接收一個 ObserverWrapper 的參數,若是不爲空就是說只用通知這個特定的觀察者,不然通知全部處於激活的觀察者。

  • setValuepostValue

setValue 直接改變當前的值,而後調用 dispatchingValue(null) 來通知全部激活狀態的觀察者,不過必須在主線程調用不然會拋異常。由於其餘線程也均可以直接改變當前值的話會形成併發,加鎖的話又會影響性能。

因此就又搞了一個 postValue,它首先在拿到同步鎖的狀況下把值存到 mPendingData,而後向主線程的 Handler 拋一個更新當前值的 mPostValueRunnable,這個 mPostValueRunnable 在執行時也是先拿同步鎖,而後調用 setValue(如今在主線程)把 mPendingData 設置到當前值。在 mPostValueRunnable 拋出去以後且還未執行前,若是再次調用 postValue 就又會修改 mPendingData 的值,而不會再次向 Handler 拋一次 mPostValueRunnable,這樣就致使了後設置的值覆蓋掉前面設置的,最後只會向觀察者們通知最新的值。這個是須要注意的點,谷歌可能認爲既然只是在主線程更新 View,那你拿最新的值就行,其餘的都無所謂,固然這樣也起到流量控制的做用,防止短期內過多的事件觸發無用的回調。

四、總結

谷歌推出的 AAC 庫很好的解決了平常使用中的生命週期問題,使咱們能夠專心於業務層面的設計,而不須要再爲生命週期等問題擔心。LiveDataViewModel 確實好用,但用的時候也有須要注意的地方,ViewModel 層實際應用中要上承 View 層,提供必要的動做和數據,下接 Model 層,作好數據處理,都有不少須要考慮的地方,以後有時間再談談我在使用 AAC 的路上的經驗和總結。
博客的 Github 倉庫 歡迎你們 Start & Fork !

相關文章
相關標籤/搜索