Jetpack系列-LiveData使用和源碼分析

1 簡介和簡單使用

1.1 簡介

LiveData是一種可觀察的數(shù)據(jù)存儲器類冠场。與常規(guī)的可觀察類不同,LiveData具有生命周期感知能力,意指它遵循其他應(yīng)用組件(如Activity娃肿、Fragment或Service)的生命周期晒杈。這種感知能力可確保LiveData僅更新處于活躍生命周期(onStart粪般、onResume)狀態(tài)的應(yīng)用組件觀察者。LiveData通常和ViewModel相結(jié)合使用。

LiveData依賴于Lifecycle,需要使用Lifecycle提供的狀態(tài)來判斷程序的活躍狀態(tài)滔蝉。

如果觀察者(由Observer類表示)的生命周期處于STARTED或RESUMED狀態(tài)螃概,則LiveData會認(rèn)為該觀察者處于活躍狀態(tài)冒窍。LiveData 只會將更新通知給活躍的觀察者。為觀察LiveData對象而注冊的非活躍觀察者不會收到更改通知圣猎。

Google官網(wǎng):https://developer.android.google.cn/topic/libraries/architecture/livedata?hl=zh_cn

1.2 簡單使用

引入依賴,按需所取应狱。

def lifecycle_version = "2.4.1"
def arch_version = "2.1.0"

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"

// Annotation processor
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"

// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"

// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"

// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"

創(chuàng)建一個單例StrLiveData年缎,里邊會實例化一個MutableLiveData坛怪,用來存儲String類型的數(shù)據(jù)怪嫌。

object StrLiveData {
    //懶加載
    val info: MutableLiveData<String> by lazy { MutableLiveData() }
}

在Activity中使用找爱。

class LiveDataActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        val tvContent = findViewById<TextView>(R.id.tv_content)

        //觀察數(shù)據(jù)變化敞贡,界面可見時迫悠,才會給TextView設(shè)置數(shù)據(jù)
        StrLiveData.info.observe(this) {
            tvContent.text = it
        }

        //觀察數(shù)據(jù)變化搁拙,不管界面可見不可見字柠,都給TextView設(shè)置數(shù)據(jù)
        //observeForever不會考慮生命周期铜异,任何狀態(tài)下都會執(zhí)行
        StrLiveData.info.observeForever {
            tvContent.text = it
        }

        //主線程修改數(shù)據(jù)
        StrLiveData.info.value = "在主線程修改的數(shù)據(jù)"

        thread {
            Thread.sleep(2000)
            //子線程修改數(shù)據(jù)
            StrLiveData.info.postValue("在子線程修改的數(shù)據(jù)")
        }
    }
}

XML文件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".jetpack.livedata.demo1.LiveDataActivity">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

1.3 關(guān)系框架

2 源碼分析

2.1 setValue 主線程修改數(shù)據(jù)

首先在業(yè)務(wù)層單例中實例化了一個MutableLiveData食茎,MutableLiveData繼承LiveData惧互,只保留setValue和postValue兩個設(shè)置數(shù)據(jù)的方法管宵,簡化使用钱床。

public class MutableLiveData<T> extends LiveData<T> {

    /**
     * Creates a MutableLiveData initialized with the given {@code value}.
     *
     * @param value initial value
     */
    public MutableLiveData(T value) {
        super(value);
    }

    /**
     * Creates a MutableLiveData with no value assigned to it.
     */
    public MutableLiveData() {
        super();
    }

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

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

當(dāng)業(yè)務(wù)層調(diào)用LiveData的setValue方法時,在主線程修改數(shù)據(jù)慌盯。

//主線程修改數(shù)據(jù)
StrLiveData.info.value = "在主線程修改的數(shù)據(jù)"</pre>

setValue方法首先會檢查當(dāng)前是否是主線程,然后會對mVersion+1掂器,接著分發(fā)數(shù)據(jù)润匙。

<pre data-language="java" id="QU8SA" class="ne-codeblock language-java" style="border: 1px solid #e8e8e8; border-radius: 2px; background: #f9f9f9; padding: 16px; font-size: 13px; color: #595959">@MainThread
protected void setValue(T value) {
    //檢查是否是主線程
    assertMainThread("setValue");
    //mVersion+1
    mVersion++;
    mData = value;
    //分發(fā)數(shù)據(jù)
    dispatchingValue(null);
}

mVersion是LiveData粘性數(shù)據(jù)特性的關(guān)鍵,它的初始值是-1唉匾。

static final int START_VERSION = -1;

public LiveData() {
     mData = NOT_SET;
     //LiveData實例化的時候給mVersion賦值為-1
     mVersion = START_VERSION;
}

分發(fā)數(shù)據(jù)的時候有兩種情況,一種是調(diào)用LiveData.observe()匠楚,另一種是調(diào)用LiveData.observeForever()巍膘。ObserverWrapper是觀察者的包裝類。

void dispatchingValue(@Nullable ObserverWrapper initiator) {
        ...
        //initiator(觀察者)不為空
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            //initiator(觀察者)為空芋簿,需要遍歷所有的觀察者
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                 mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
       ...
}

接下來調(diào)用considerNotify方法峡懈。然后對當(dāng)前是否是活躍狀態(tài)進行檢查,也就是mActive是否為true与斤。為true才會繼續(xù)執(zhí)行肪康。就這對mVersion進行對比,由于在setValue的時候mVersion++之后變?yōu)?撩穿,mLastVersion為-1磷支,所以這里observer.mLastVersion >= mVersion不成立,數(shù)據(jù)會正常分發(fā)出去食寡,這就是造成粘性數(shù)據(jù)特征的原因雾狈。

如果調(diào)用LiveData.observe(),那么當(dāng)Lifecycle狀態(tài)為STARTED和RESUMED抵皱,也就是Activity/Fragment生命周期為onStart和onResume的時候善榛,mActive=true辩蛋,其他狀態(tài)和生命周期下,mActive=fale移盆;如果調(diào)用LiveData.observeForever()悼院,mActive一直為true,這就實現(xiàn)了調(diào)用LiveData.observeForever()時候咒循,觀察者不會去考慮生命周期和狀態(tài)据途,所有數(shù)據(jù)都會無條件感知。

private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        //判斷mActivie是否為true剑鞍。
        //調(diào)用LiveData.observe()時會根據(jù)狀態(tài)和生命周期計算mActive的值;
        //調(diào)用LiveData.observeForever()時mActive一直為true昨凡。
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //判斷mVersion
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //回調(diào)數(shù)據(jù)給觀察者
        observer.mObserver.onChanged((T) mData);
}

2.2 postValue 子線程修改數(shù)據(jù)

當(dāng)業(yè)務(wù)層調(diào)用LiveData的postValue方法時,在子線程修改數(shù)據(jù)蚁署。

thread {
    ...
    //子線程修改數(shù)據(jù)
    StrLiveData.info.postValue("在子線程修改的數(shù)據(jù)")
}

postValue方法中最終也會通過Handler切換到主線程便脊。

protected void postValue(T value) {
    boolean postTask;
    //加鎖,防止線程安全問題
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    //切換到主線程
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

在ArchTaskExecutor中光戈,會實例化一個DefaultTaskExecutor哪痰,然后調(diào)用DefaultTaskExecutor的postToMainThread方法。

private ArchTaskExecutor() {
    mDefaultTaskExecutor = new DefaultTaskExecutor();
    mDelegate = mDefaultTaskExecutor;
}

@Override
public void postToMainThread(Runnable runnable) {
    mDelegate.postToMainThread(runnable);
}

DefaultTaskExecutor使用Handler進行線程間通信久妆,實現(xiàn)子線程到主線程切換晌杰。

@Override
public void postToMainThread(Runnable runnable) {
    if (mMainHandler == null) {
        synchronized (mLock) {
            if (mMainHandler == null) {
                mMainHandler = new Handler(Looper.getMainLooper());
            }
        }
    }
    //noinspection ConstantConditions
    mMainHandler.post(runnable);
}

而在postToMainThread中傳入的Runnable中,最紅也調(diào)用了setValue筷弦,接下來的邏輯就和主線程中修改數(shù)據(jù)一致了肋演。

private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        //最終也是調(diào)用setValue
        setValue((T) newValue);
    }
};

2.3 observe 根據(jù)生命周期感知數(shù)據(jù)變化

調(diào)用LiveData的observe( LifecycleOwner owner, Observer<? super T> observer)方法時,傳入了一個被觀察者和觀察者烂琴。

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    //檢查是否是主線程
    assertMainThread("observe");
    //獲取Lifecycle當(dāng)前狀態(tài)爹殊,如果是銷毀狀態(tài),那就忽略奸绷,不再繼續(xù)往下進行
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        return;
    }
    //創(chuàng)建一個LifecycleBoundObserver對象梗夸,包裝了LifecycleOwner和Observer。
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //ObserverWrapper包裝了LifecycleBoundObserver和Observer
    //把Observer和LifecycleBoundObserver存入map
    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);
}

LifecycleBoundObserver是LiveData的內(nèi)部類号醉,繼承了ObserverWrapper反症,并且實現(xiàn)LifecycleObserver。傳入了一個被觀察者和觀察者畔派。

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    //傳入被觀察者和觀察者
    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        //從Lifecycle獲取到當(dāng)前是否是活躍狀態(tài)(UI可見狀態(tài))铅碍。
        //Activity/Fragment生命周期onStart和onResume,Lifecycle對應(yīng)狀態(tài)為STARTED和RESUMED時线椰,處于活躍狀態(tài)该酗。
        //這里使用了一個比較,也就是狀態(tài)在STARTED和STARTED之后時,就處于活躍狀態(tài)呜魄。
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
                               @NonNull Lifecycle.Event event) {
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        if (currentState == DESTROYED) {
            //頁面銷毀時悔叽,移除觀察者
            removeObserver(mObserver);
            return;
        }
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            //調(diào)用ObserverWrapper的activeStateChanged,再調(diào)用dispatchingValue分發(fā)數(shù)據(jù)爵嗅。
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        //觀察者和被觀察者解除綁定
        mOwner.getLifecycle().removeObserver(this);
    }
}

ObserverWrapper是LiveData的抽象內(nèi)部類娇澎。

private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;

    ObserverWrapper(Observer<? super T> observer) {
        mObserver = observer;
    }

    //抽象方法,判斷是否處于活躍狀態(tài)
    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        mActive = newActive;
        changeActiveCounter(mActive ? 1 : -1);
        if (mActive) {
            //處于活躍狀態(tài)睹晒,發(fā)送最新的值
            dispatchingValue(this);
        }
    }
}

2.3 observeForever 無條件感知數(shù)據(jù)變化

在調(diào)用LiveData的observeForever方法時趟庄,沒有傳入被觀察者,值傳入了觀察者伪很,這就決定了調(diào)用observeForever之后無法根據(jù)Activity/Fragment的生命周期去判斷合適感知數(shù)據(jù)戚啥,只能無條件的接收所有數(shù)據(jù)。這里用AlwaysActiveObserver對觀察者進行了包裝锉试。

@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    //判斷是否是主線程
    assertMainThread("observeForever");
    //創(chuàng)建一個AlwaysActiveObserver對象猫十,對Observer進行包裝
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    //ObserverWrapper包裝了AlwaysActiveObserver和Observer
    //把Observer和AlwaysActiveObserver存入map
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing instanceof LiveData.LifecycleBoundObserver) {
        throw new IllegalArgumentException("Cannot add the same observer"
                                           + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    //這里傳入的mActive一直是true,所以消息一直能無條件回調(diào)給觀察者
    wrapper.activeStateChanged(true);
}

再看AlwaysActiveObserver呆盖,shouldBeActive固定返回true拖云。所以在considerNotify方法中,一直能執(zhí)行到observer.mObserver.onChanged((T) mData)应又,把數(shù)據(jù)回調(diào)給觀察者宙项。

private class AlwaysActiveObserver extends ObserverWrapper {

    AlwaysActiveObserver(Observer<? super T> observer) {
        super(observer);
    }

    @Override
    boolean shouldBeActive() {
        return true;
    }
}

3 流程圖

根據(jù)上邊的源碼分析,畫出以下流程圖株扛。


關(guān)注木水小站 (zhangmushui.cn)和公眾號【木水Code】尤筐,及時獲取更多技術(shù)干貨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洞就,一起剝皮案震驚了整個濱河市叔磷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奖磁,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件繁疤,死亡現(xiàn)場離奇詭異咖为,居然都是意外死亡,警方通過查閱死者的電腦和手機稠腊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門躁染,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人架忌,你說我怎么就攤上這事吞彤。” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵饰恕,是天一觀的道長挠羔。 經(jīng)常有香客問我,道長埋嵌,這世上最難降的妖魔是什么破加? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮雹嗦,結(jié)果婚禮上范舀,老公的妹妹穿的比我還像新娘。我一直安慰自己了罪,他們只是感情好锭环,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泊藕,像睡著了一般辅辩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吱七,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天汽久,我揣著相機與錄音,去河邊找鬼踊餐。 笑死景醇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吝岭。 我是一名探鬼主播三痰,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼窜管!你這毒婦竟也來了散劫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤幕帆,失蹤者是張志新(化名)和其女友劉穎获搏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體失乾,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡常熙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碱茁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裸卫。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖纽竣,靈堂內(nèi)的尸體忽然破棺而出墓贿,到底是詐尸還是另有隱情茧泪,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布聋袋,位于F島的核電站队伟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏舱馅。R本人自食惡果不足惜缰泡,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望代嗤。 院中可真熱鬧棘钞,春花似錦、人聲如沸干毅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硝逢。三九已至姨拥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渠鸽,已是汗流浹背叫乌。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留徽缚,地道東北人憨奸。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像凿试,于是被迫代替她去往敵國和親排宰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容