最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

DEVLOG 11.10 LiveData 源碼解析 + LiveDataBus處理粘性事件

2021-11-11 20:29 作者:房頂上的鋁皮水塔  | 我要投稿

參考內(nèi)容:

1.?你們要的LiveData&lifecycle原理解析來(lái)了!

2. Activity And Fragment 生命周期?

https://blog.piasy.com/2017/01/14/Android-Basics-Activity-Fragment-Life-Cycle/index.html

這篇文章真的很值得一看,這篇文章基于參考內(nèi)容基礎(chǔ)上,添加了我自己在看LiveData源碼的很多思考,要是大家覺(jué)得我講的清楚,說(shuō)的有趣,可以一鍵三連支持一下子嗷!

內(nèi)容分成以下幾個(gè)方面:

  1. 復(fù)習(xí)一下觀察者模式

    1. LiveData觀察的對(duì)象是什么?

    2. LiveData和Kotlin的觀察者模式的區(qū)別可以說(shuō)一下嘛?

  2. LiveData observe和setValue postValue源碼解析

  3. LiveData的live體現(xiàn)在哪里?

  4. LiveDataBus實(shí)現(xiàn),并且消除粘性事件


Part1 復(fù)習(xí)一下觀察者模式

來(lái),比劃比劃!整一個(gè)觀察者模式還不是輕輕松松?

觀察者模式肯定要分為兩個(gè)角色,一個(gè)是Observable 被觀察者,另外一個(gè)是Observer 觀察者,觀察者不能直接感知被觀察者中的數(shù)據(jù)變化,所以需要被觀察者拿到Observable的引用,然后數(shù)據(jù)變化的時(shí)候通知就完事了,基礎(chǔ)的觀察者模式可以這樣寫:

好像Kotlin中也有【觀察者模式】,稍微看看Kotlin中觀察者模式和這個(gè)的區(qū)別:

其實(shí)Kotlin中的【觀察者模式】是使用代理模式實(shí)現(xiàn)的,代理模式在Kotlin中使用by關(guān)鍵字表示,舉個(gè)簡(jiǎn)單的例子:


所以Kotlin中的觀察者模式是這樣子:

接下來(lái)進(jìn)入我們今天的正題,LiveData的基本使用:

LiveData基本使用

LiveData之所以【Live】是因?yàn)樗梢詫?duì)于組件生命周期有所把控,同時(shí),如果數(shù)據(jù)發(fā)生變化可以執(zhí)行預(yù)設(shè)的回調(diào)函數(shù),下面我們看看他的基本使用:

所以相當(dāng)于是將一個(gè)值【存儲(chǔ)】在LiveData中,發(fā)生改變(setValue),LiveData就會(huì)調(diào)用定義的【observer lambda】,因?yàn)镵otlin的語(yǔ)法特性支持如果最后一個(gè)參數(shù)是interface的話可以定義在括號(hào)外邊,就像一個(gè)lambda,所以我下文都會(huì)稱這個(gè)回調(diào)函數(shù)為【observer?lambda】

當(dāng)然,如果不在主線程中,還可以使用postValue:


在這個(gè)例子中LiveData中,觀察者模式體現(xiàn)的比較明顯,【Live】指的是只有當(dāng)生命周期容器處于前臺(tái)的狀態(tài)【active】,才可以會(huì)調(diào)用observer lambda。

Part2: LiveData observe和setValue/postValue源碼解析

根據(jù)我們的基本操作來(lái)看,我們一般會(huì)在Activity中創(chuàng)建LiveData,然后會(huì)使用LiveData#observe寫一個(gè)如果被觀察的數(shù)據(jù)改變了的回調(diào)。通過(guò)LiveData#setValue 改變數(shù)據(jù),如果數(shù)據(jù)出現(xiàn)變化,剛才在LiveData#observe中寫的回調(diào)就回被觸發(fā)。我們首先來(lái)看看LiveData#observe是如何實(shí)現(xiàn)的:

粗看這個(gè)代碼發(fā)現(xiàn)里面涉及的角色非常多,我們首先解釋一下各個(gè)角色之間的關(guān)系:

從上面的代碼可以看出,傳入的Observer 接口的實(shí)現(xiàn)類(observer lambda)會(huì)被包裝成為L(zhǎng)ifecycleBoundObserver。LifecycleBoundObserver繼承了ObserverserWrapper,同時(shí)實(shí)現(xiàn)了LifecycleEventObserver:

所以LifecycleBoundObserver實(shí)際上是一個(gè)裝飾器模式的體現(xiàn),同時(shí)因?yàn)長(zhǎng)ifecycleBoundObserver持有當(dāng)前的Lifecycle組件的引用(lifecycleOwner),因此,這個(gè)對(duì)象可以得到當(dāng)前的生命周期情況。


你們看,這個(gè)Observer是不是一個(gè)渣男?一手抓著Lifecycle組件,另外一只手持有著回調(diào)的observer lambda

行 了解完了LifecycleBoundObserver,我們繼續(xù)看代碼:

以上的代碼中有幾個(gè)需要注意的點(diǎn):

  1. observe這個(gè)方法只能用于主線程

  2. observe會(huì)檢測(cè)當(dāng)前l(fā)ifecycle組件的生命周期狀態(tài)

  3. 包裝完成observer之后,會(huì)放到一個(gè)map中

所以,這個(gè)就是一個(gè)中規(guī)中矩注冊(cè)監(jiān)聽(tīng)的行為。

LiveData#setValue LiveData#postValue

首先給一個(gè)總結(jié)setValue和postValue的差別就在于是否可以跨線程:

在postValue中,ArchTaskExecutor最后會(huì)調(diào)用postToMainThread,其實(shí)這個(gè)方法是交給通過(guò)主線程的Looper構(gòu)建的Handler完成的:


繼續(xù)分析setValue的源碼,setValue和相關(guān)調(diào)用方法組成了這樣一條調(diào)用鏈:

兩個(gè)方法具體的代碼如下:

其實(shí)LiveData也沒(méi)有那么神奇,considerNotify會(huì)根據(jù)當(dāng)前的Activity的狀態(tài)決定是否要調(diào)用回調(diào),屬于是一個(gè)看門狗了。

是不是很簡(jiǎn)單?

我們來(lái)看一個(gè)和Activity生命周期有關(guān)的例子。LiveDataActivity監(jiān)聽(tīng)從LiveDataActivity2中發(fā)來(lái)的消息,先進(jìn)入的頁(yè)面是LiveDataActivity:

LiveDataActivity2中給LiveDataActivity發(fā)送一條消息:

當(dāng)我們點(diǎn)擊textView2的時(shí)候,并沒(méi)有馬上彈出Toast,只有當(dāng)我們回到LiveDataActivity的時(shí)候才會(huì)彈出Toast。 有人會(huì)說(shuō),這不是因?yàn)門oast的代碼寫在LiveDataActivity*,那你仔細(xì)想想,是因?yàn)檫@個(gè)原因才不會(huì)彈出的嗎?


這個(gè)問(wèn)題的分析可以看出LiveData的【Live】是怎么體現(xiàn)的,具體需要看看Lifecycle的事件分發(fā)。

Part3:Lifecycle的事件分發(fā)

Acitvity在高版本的SDK中,大家都知道,他是一個(gè)LifecycleOwner,一直找Activity的父類會(huì)找到ComponentActivity:

下面,我們以ComponentActivity的onCreate方法為例,看看Lifecycle如何分發(fā)事件。


垂簾聽(tīng)政のReportFragment

從上面的onCreate方法中可以看出,會(huì)調(diào)用ReportFragment.injectIfNeededIn,我們看看ReportFragment是個(gè)什么東西:

可以看出在這個(gè)injectIfNeededIn中,如果沒(méi)有創(chuàng)建ReportFragment就會(huì)創(chuàng)建一個(gè),而且在這個(gè)類中,沒(méi)有重寫onCreateView方法,所以ReportFragment是一個(gè)沒(méi)有界面的Fragment,專門用來(lái)監(jiān)聽(tīng)綁定的Activity的生命周期,他的具體的操作實(shí)現(xiàn)就是在自己的生命周期回調(diào)中調(diào)用dispatch方法分發(fā)事件。



當(dāng)前的Fragment沒(méi)有重寫onCreateView,那我們可以看看onActivityCreated方法:

所以,在onActivityCreated中調(diào)用了dispatch,發(fā)送了一條Lifecycle ON_CREATE的消息。

如果我們按照dispatch繼續(xù)往下看調(diào)用方法的話,會(huì)得到這樣一條調(diào)用鏈:

看到最后的LifecycleEventObserver,他調(diào)用了onStateChanged方法,這個(gè)實(shí)際上就是我們通過(guò)observe方法中傳入的lambda。(前面說(shuō)過(guò),我們通過(guò)observe方法傳入的observer會(huì)被包裝成LifecycleBoundObserver)。 然后從LifecycleBoundObserver開(kāi)始,最后還會(huì)去considerNotify進(jìn)行一次判定,這次Activity是Active狀態(tài)了,可以調(diào)用回調(diào)。


因此我們可以總結(jié)一下,有這樣的兩條線路:

1.同一個(gè)Activity:

liveData.observe(回調(diào)lambda) -> liveData.setValue() -> liveData.dispatchingValue() -> liveData.considerNotify() -> 回調(diào)執(zhí)行?

在considerNotify中會(huì)考慮當(dāng)前的Activity的狀態(tài)(mActive),如果Active,就回走下面的回調(diào),


2. 不同的Activity:

LiveDataActivity2?向目前onPause的LiveDataActivity 發(fā)送消息:

liveData.observe(回調(diào)lambda) -> liveData.setValue() -> liveData.dispatchingValue() -> liveData.considerNotify() -> Activity A不是Active 不執(zhí)行 observer lambda


Activity回到前臺(tái),可見(jiàn)性恢復(fù):

ReportFragment#onResume ->??ReportFragment#dispatch -> ...... -> LifecycleEventObserver#onStateChanged ->?activeStateChanged -> dispatchingValue -> considerNotify?-> observer lambda 的回調(diào)



補(bǔ)充一下,不只是onActivityCreated,ReportFragment#onResume中和其他的生命周期方法都會(huì)調(diào)用dispatch函數(shù)的:

哇 好累!?


總結(jié)一下:

LiveData的數(shù)據(jù)的更新需要兩個(gè)條件:

  1. 通過(guò)LiveData#setValue postValue更新

  2. observer持有的lifecycle是active狀態(tài)


好了,我們現(xiàn)在屬于是知道了LiveData和Lifecycle的關(guān)系。Lifecycle其實(shí)和Glide有異曲同工指出,設(shè)置了一個(gè)空的ReportFragment看Activity的生命周期,在不同的Fragment生命周期函數(shù)發(fā)送消息給LifecycleRegistry,最后還是通過(guò)considerNotify 這條看門狗決定是否能調(diào)用observer lambda回調(diào):

considerNotify回調(diào)的時(shí)候?qū)Data,也就是我們通過(guò)setValue傳入的結(jié)果當(dāng)做參數(shù)進(jìn)行回調(diào)。mData被定義為了一個(gè)volatile變量,volatile變量有一個(gè)特點(diǎn),就是可以【穿越線程】,及時(shí)更新變量的值。


有人可能會(huì)想,setValue只會(huì)在主線程中調(diào)用,不會(huì)進(jìn)行任何的多線程操作,為什么要設(shè)置mData為violatie呢?這里之所以要設(shè)置為volatile變量,還要結(jié)合LiveData中可以在子線程中操作的api postValue來(lái)看:

mPendingData的初始值就是NOT_SET,在mPostValueRunnable中如果執(zhí)行玩這個(gè)Runnable,會(huì)給這個(gè)mPendingData在賦值為NOT_SET。

注意下,在postValue中的synchroized都是對(duì)象鎖,而且對(duì)象是同一個(gè)。

下面我們來(lái)簡(jiǎn)單分析一下為啥要加入這個(gè)volatile關(guān)鍵字:

如果存在volatile變量,線程AB會(huì)立刻知道變量的變化,兩個(gè)線程并發(fā)使用postValue的時(shí)候,可能只有一個(gè)線程能夠正確將value更新,但是不會(huì)造成寫錯(cuò)的情況:

加入mPendingData不是volatile的:


按照順序依次往下看,當(dāng)mPendingData在A線程中被修改成valueA,但是還沒(méi)來(lái)得及寫回主內(nèi)存時(shí),B可能先一步執(zhí)行寫回操作,這樣在A拿到Lock#2,也就是runnable中的控制權(quán)之后,A會(huì)寫入valueB。這樣就錯(cuò)亂了


設(shè)置mData和mPendingData為volatile就是為了避免這個(gè)問(wèn)題。

實(shí)現(xiàn)一個(gè)LiveDataBus

讓我們來(lái)簡(jiǎn)單測(cè)試一下這個(gè)LiveDataBus。

有兩個(gè)Activity,LiveDataActivity給LiveDataActivity2中發(fā)送一個(gè)值。

按照我們的想法, LiveDataActivity2此時(shí)剛跳轉(zhuǎn)的話是不應(yīng)該接受數(shù)據(jù),因?yàn)橹翱赡芤矔?huì)有發(fā)送數(shù)據(jù)的情況,但是此時(shí)LiveDataActivity2沒(méi)有訂閱,這些數(shù)據(jù)不需要。但是以上的代碼當(dāng)跳轉(zhuǎn)到Activity2之后,Toast會(huì)立刻彈出。


這不符合我們的需求,這就是一個(gè)粘性事件。我們不應(yīng)該在訂閱之后收到訂閱之前的數(shù)據(jù),好比晚上七點(diǎn)開(kāi)始看新聞聯(lián)播,但是一開(kāi)電視就給你放中午的【今日說(shuō)法】,是不是特別煩人?


我們來(lái)著手解決這個(gè)問(wèn)題:

解決粘性事件

通過(guò)上面一張流程圖,我們可以看出,是considerNotify這條看門狗之所以會(huì)觸發(fā)沒(méi)有observe的LiveDataActivity2的回調(diào)是因?yàn)榇鎯?chǔ)在LiveDataBus中的LiveData實(shí)例,他的mVersion大于ObserverWrapper中的mLastVersion。

因?yàn)閟etValue會(huì)使得mVersion++,并且我們不知道setValue和observe哪一個(gè)會(huì)先調(diào)用;所以如果我們可以在observe的時(shí)候?qū)Version == mLastVersion,就可以解決這個(gè)問(wèn)題。

解決問(wèn)題的關(guān)鍵-- Hook

Hook其實(shí)就是使用了反射技術(shù),解決問(wèn)題的關(guān)鍵就在obsever.mLastVersion上,我們可以往上溯源,發(fā)現(xiàn)最終和LiveData類中的mObservers屬性有關(guān),接著,我們就可以使用反射機(jī)制寫出如下的代碼:


DEVLOG 11.10 LiveData 源碼解析 + LiveDataBus處理粘性事件的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
乌鲁木齐市| 柳江县| 青阳县| 苗栗县| 威信县| 成都市| 丰顺县| 云林县| 汉川市| 海盐县| 玛多县| 瑞金市| 武宁县| 株洲市| 张家口市| 颍上县| 民权县| 方城县| 礼泉县| 韶关市| 石城县| 久治县| 曲麻莱县| 贡嘎县| 白水县| 东宁县| 全椒县| 应城市| 江门市| 海宁市| 舒兰市| 广南县| 理塘县| 巩义市| 双辽市| 淳化县| 黄平县| 康马县| 永年县| 嵊泗县| 民丰县|