天天看點

Android架構元件四 Android Architecture Components LiveData元件解析

1 前言

簡單的說,LiveData是一個資料持有類,持有的資料可被觀察者觀察。它具有以下特點

  • 資料可以被觀察者訂閱;
  • 能夠感覺元件(Fragment、Activity、Service)的生命周期;
  • 隻有在元件出于激活狀态(STARTED、RESUMED)才會通知觀察者有資料更新;

當然這裡的元件都是指實作了LifecycleOwner接口的元件。

官方推薦我們使用LiveData時結合ViewModel來使用,進而達到解耦的目的。那麼為什麼需要使用LiveData呢?或者說,使用LiveData能給我們帶來什麼好處呢?

2 LiveData的功能

從官方文檔來看,LiveData的使用有以下幾大好處

  • 保證UI狀态和資料的統一

LiveData采用了觀察者設計模式。當生命周期狀态改變時,LiveData會通知Observer對象。每次應用程式資料更改時,都會通知觀察者對象,進而更新UI。

  • 減少記憶體洩漏

LiveData能夠感覺到元件的生命周期,觀察者綁定到生命周期對象,并在其相關生命周期被破壞後自行清理。

  • 當Activity停止時不會引起崩潰

這是因為元件處于非激活狀态時,不會收到LiveData中資料變化的通知

  • 不需要額外的手動處理來響應生命周期的變化

這一點同樣是因為LiveData能夠感覺元件的生命周期,是以就完全不需要在代碼中告訴LiveData元件的生命周期狀态。

  • 元件和資料相關的内容能實時更新

元件在前台的時候能夠實時收到資料改變的通知,這是可以了解的。當元件從背景到前台來時,LiveData能夠将最新的資料通知元件,這兩點就保證了元件中和資料相關的内容能夠實時更新。

  • 針對configuration change時,不需要額外的處理來儲存資料

我們知道,當你把資料存儲在元件中時,當configuration change(比如語言、螢幕方向變化)時,元件會被recreate,然而系統并不能保證你的資料能夠被恢複的。當我們采用LiveData儲存資料時(結合ViewModel),因為資料群組件分離了。當元件被recreate,資料還是存在LiveData中,并不會被銷毀。

  • 資源共享

通過繼承LiveData類,然後将該類定義成單例模式,在該類封裝監聽一些系統屬性變化,然後通知LiveData的觀察者,例如下面的例子

/**
 * @author Created by qiyei2015 on 2018/2/25.
 * @version: 1.0
 * @email: [email protected]
 * @description: 監聽網絡是否連接配接的LiveData
 */
public class NetworkLiveData extends LiveData<Integer> {


    private static NetworkLiveData sNetworkLiveData;

    private WeakReference<Context> mContextWeakReference;

    private NetworkChangeReceiver mChangeReceiver;

    private NetworkLiveData(Context context){
        mContextWeakReference = new WeakReference<Context>(context);
    }

    /**
     * DCL 方式單例
     * @return
     */
    public static NetworkLiveData getInstance(Context context){
        if (sNetworkLiveData == null){
            synchronized (NetworkLiveData.class){
                if (sNetworkLiveData == null){
                    sNetworkLiveData = new NetworkLiveData(context);
                }
            }
        }
        return sNetworkLiveData;
    }

    /**
     * observer 從0 到1 調用
     */
    @Override
    protected void onActive() {
        super.onActive();
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        mChangeReceiver = new NetworkChangeReceiver();
        mContextWeakReference.get().registerReceiver(mChangeReceiver, filter);
    }

    /**
     * observer 從1 到0 調用
     */
    @Override
    protected void onInactive() {
        super.onInactive();
        mContextWeakReference.get().unregisterReceiver(mChangeReceiver);
    }

    /**
     * 網絡狀态變更的廣播
     */
    private class NetworkChangeReceiver extends BroadcastReceiver {

        public final int wifi = , mobile = , none = ;
        public int oldState = none;

        /**
         * 觸發網絡狀态監聽回調
         *
         * @param nowStatus 目前網絡狀态
         */
        private void setChange(int nowStatus) {
            oldState = nowStatus;
            sNetworkLiveData.setValue(oldState);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mobNetInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
            NetworkInfo wifiNetInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            if (!mobNetInfo.isConnected() && !wifiNetInfo.isConnected()) {
                Log.i("通知", "網絡不可以用");
                setChange(none);
            } else if (mobNetInfo.isConnected()) {
                Log.i("通知", "僅移動網絡可用");
                setChange(mobile);
            } else if (wifiNetInfo.isConnected()) {
                Log.i("通知", "Wifi網絡可用");
                setChange(wifi);
            }
        }
    }


}
           

其中

onActive(),此方法是當處于激活狀态的observer個數從0到1時,該方法會被調用。

onInactive() ,此方法是當處于激活狀态的observer個數從1變為0時,該方法會被調用。

這樣子,在任何Activity/Fragment中我們都可以使用如下方式來觀察網絡狀态變化

NetworkLiveData.getInstance(this).observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer networkState) {
                //your code
            }
        });
           

注意,這裡我們并沒有顯式在Activity/Fragment 中移除LiveData的監聽,因為LiveData可以自動的幫我們處理這個過程

3 LiveData類圖

LiveData的類圖如下:

Android架構元件四 Android Architecture Components LiveData元件解析

可以看到,主要涉及到的類就是LiveData,MutableLiveData,LifecycleBoundObserver,Observer。其他的類已在LifeCycle中介紹過了。

我們先來看LiveData

LiveData< T >是一個抽象的泛型類,主要提供以下幾個方法

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)//添加觀察者
@MainThread
public void observeForever(@NonNull Observer<T> observer)//添加永久的觀察者,不考慮是否處于激活狀态
@MainThread
public void removeObserver(@NonNull final Observer<T> observer)//移除觀察者
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner)//移除被觀察的對象
@Nullable
public T getValue()//擷取持有的資料
public boolean hasObservers()//是否有觀察者
public boolean hasActiveObservers()//是否有活躍的觀察者
           

MutableLiveData

MutableLiveData繼承自LiveData,源碼如下,主要将postValue和setValue設定為Public。

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}
           

LifecycleBoundObserver

LifecycleBoundObserver是LiveData的内部類,實作于GenericLifecycleObserver接口,該接口又繼承LifecycleObserver接口,主要用于LiveData添加觀察者時,包裝LifecycleOwner和Observer使用

class LifecycleBoundObserver implements GenericLifecycleObserver {
        public final LifecycleOwner owner;
        public final Observer<T> observer;
        public boolean active;
        public int lastVersion = START_VERSION;

        LifecycleBoundObserver(LifecycleOwner owner, Observer<T> observer) {
            this.owner = owner;
            this.observer = observer;
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (owner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(observer);
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == active) {
                return;
            }
            active = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == ;
            LiveData.this.mActiveCount += active ?  : -;
            if (wasInactive && active) {
                onActive();
            }
            if (LiveData.this.mActiveCount ==  && !active) {
                onInactive();
            }
            if (active) {
                dispatchingValue(this);
            }
        }
    }
           

根據前面的分析,Activity/Fragment均實作了LifecycleOwner接口,并且當Activity/Fragment 生命周期變化時會發送相應的事件到LifecycleObserver的執行個體,是以,當Activity/Fragment生命周期變化時,最終會回調到LifecycleBoundObserver 的onStateChanged(LifecycleOwner source, Lifecycle.Event event)方法。關于這一點可以參考

Android架構元件二 Android Architecture Components Lifecycles 元件解析

4 LiveData解析

LiveData我覺得弄清楚以下幾個問題就可以了。

1 LiveData如何添加觀察者?

我們直接從observe(@NonNull LifecycleOwner owner, @NonNull Observer< T> observer)開始分析

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing.owner != wrapper.owner) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }
           

首先根據LifecycleOwner 和Observer構造LifecycleBoundObserver 對象wrapper,然後将其添加到SafeIterableMap

實際上調用的是Activity/Fragment 中的LifecycleRegistry mLifecycleRegistry來添加觀察者,最終會調用到LifecycleRegistry中的addObserver(@NonNull LifecycleObserver observer)

LifecycleRegistry.java

@Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        if (previous != null) {
            return;
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

        boolean isReentrance = mAddingObserverCounter !=  || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }
           

這樣,最終Activity/Fragment的生命周期變化會被LifecycleBoundObserver 觀察到,這個和我們上面的分析一緻。

同理LiveData的removeObserver(@NonNull final Observer< T> observer)邏輯也類似。最終會在LifecycleRegistry 中移除對Activity/Fragment的觀察。

這樣,添加和移除觀察者的邏輯就理清楚了。

2 LiveData如何感覺元件生命周期?

根據前面的分析,當LifecycleOwner的實作者Activity/Fragment 的生命周期變化,由于添加了LifecycleBoundObserver,是以最終會回調到LifecycleBoundObserver#onStateChanged(LifecycleOwner source, Lifecycle.Event event)方法

class LifecycleBoundObserver implements GenericLifecycleObserver {
        public final LifecycleOwner owner;
        public final Observer<T> observer;
        public boolean active;
        public int lastVersion = START_VERSION;

        LifecycleBoundObserver(LifecycleOwner owner, Observer<T> observer) {
            this.owner = owner;
            this.observer = observer;
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (owner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(observer);
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == active) {
                return;
            }
            active = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == ;
            LiveData.this.mActiveCount += active ?  : -;
            if (wasInactive && active) {
                onActive();
            }
            if (LiveData.this.mActiveCount ==  && !active) {
                onInactive();
            }
            if (active) {
                dispatchingValue(this);
            }
        }
    }
           

可以看到onStateChanged(LifecycleOwner source, Lifecycle.Event event)的邏輯如下:

1 首先判斷LifecycleOwner 的狀态時候是DESTROYED,如果是直接移除觀察者,這樣就幫我們在LifecycleOwner 中移除了觀察者,減少了很多重複性的代碼

2 判斷LifecycleOwner 的狀态是否是Active,并根據mActiveCount Observer 的個數和Active狀态開始回調onActive()或者onInactive()方法

3 如果activeStateChanged(boolean newActive)中判斷到LifecycleOwner 的狀态是Active,就調用dispatchingValue(this);進行資料的分發。最終會調用到LiveData的如下方法

private void considerNotify(LifecycleBoundObserver observer) {
        if (!observer.active) {
            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 (!isActiveState(observer.owner.getLifecycle().getCurrentState())) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.lastVersion >= mVersion) {
            return;
        }
        observer.lastVersion = mVersion;
        //noinspection unchecked
        observer.observer.onChanged((T) mData);
    }
           

首先會判斷LifecycleOwner是否處于前台,然後會調用

這樣子會調用到Observer的onChanged(@Nullable T t)方法。

這樣子就解釋了為什麼LifecycleOwner隻有在前台才會收到資料更新。

有關LiveData的分析就暫時結束了,有關Android架構元件的分析也告一段落了,關于Room資料庫元件暫時還沒有用到。後續再寫文章分析吧。

參考:

https://developer.android.google.cn/topic/libraries/architecture/livedata.html

https://shymanzhu.com/2017/12/23/Android%E6%9E%B6%E6%9E%84%E7%BB%84%E4%BB%B6%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94LiveData/#more