1. 程式人生 > >Android學習筆記—— EventBus 原始碼解析

Android學習筆記—— EventBus 原始碼解析

最近專案裡用到的EventBus 更新到了 3.0,學習了一下EventBus 3.0 的原始碼,發現3.0版本較之前版本變化還是相對較大的,無論從效能上,還是使用流程上。恰好組內分享輪到我,所以就做了一次EventBus 3.0的原始碼解析。

 

 EventBus 是 事件釋出/訂閱 匯流排,是一種超低耦合的訊息傳遞方式,很多專案都在用它啦,用法就不講了,從原始碼裡講講具體實現,順帶講講用它的時候需要注意的地方。

 EventBus 從使用流程上來說,大致可分為三步:register, post, unregister。下面就分佈來看看EventBus的原始碼。

一. register



 該方法首先獲取獲取傳進來引數的Class物件,然後根據這個引數通過subscriberMethodFinder.findSubscriberMethods方法獲取所有的事件處理方法。老的版本里還有對傳進來的類是否是匿名類的判斷,3.0正式版相容了對於匿名類的處理。另外要說的是,從3.0版本開始,統一了register 入口,之前版本還有對register的過載入口以及registerSticky入口等,有些複雜而且在是否sticky上容易出錯。


可以見到在 3.0 beta版本里,作者已經在著手加入index以減少遍歷訂閱方法時的效能消耗了,但是真正加入索引查詢是在 3.0的正式版本里。

我們可以看出,在3.0beta 和 3.0兩個版本中,該函式的實現過程還是大有不同的。加上索引查詢以後,利用索引查詢以及快取查詢以及能找到大部分訂閱方法,這樣就大大減小了進入 findUsingReflection()方法的查詢流量,畢竟在該方法裡,查詢到我們所要的訂閱方法集合,我們需要用反射的方法去遍歷每一個類的每個方法,然後找出訂閱該事件的訂閱方法,很耗時,可能會ANR.

為了能使3.0的EventBus 產生索引,需在專案 build.gradle 中加入 圖中第二句的依賴。



找到事件處理函式後,會遍歷找到的所有事件處理函式並呼叫subscribe方法將所有事件處理函式註冊到

EventBus.裡主要注意checkPostStickyEventToSubscription這個方法,這個方法是統一register入口的關鍵,它處理了sticky事件。從而可以在3.0中去掉registerSticky方法。可以看到,如果是黏性事件,會執行postToSubscription方法,這就該講post事件的具體實現流程了。

二. post


在post方法中,首先會將event物件新增到事件佇列eventQueue中。然後判斷是否有事件正在post,如果沒有則會遍歷eventQueue中每一個event物件,並且呼叫postSingleEvent方法post該事件。而postSticky 是在執行post之前快取傳來的event 在一個 stickyEvents 列表裡。

eventInheritance標識該事件是否可以被繼承,若為true則會去查詢所有該事件的父類和介面類,並將其儲存到eventTypesCache中,方便下次使用。不管允不允許事件繼承,都會執行postSingleEventForEventType方法post事件。


在postSingleEventForEventType方法中,會已eventClass為key從subscriptionsByEventType物件中獲取Subscription列表。在上面講register的時候我們已經看到EventBus在register的時候會將Subscription列表儲存在subscriptionsByEventType中。接下來會遍歷subscriptions列表然後呼叫postToSubscription方法進行下一步處理。這裡的postToSubscription就接上了 在 register 流程裡所講的,當事件為sticky事件時,會執行postToSubscription 方法將該事件post出去。。而引數則來自於快取list stickyEvents,詳見 register流程 subscribe 函式;


該方法主要是根據register註冊的事件處理函式的執行緒模型在指定的執行緒中觸發事件處理函式。mainThreadPoster、backgroundPoster和asyncPoster分別是HandlerPoster、BackgroundPoster和AsyncPoster的物件,其中HandlerPoster繼承自Handle,BackgroundPoster和AsyncPoster繼承自Runnable。這裡就要說到EventBus中的四中執行緒模型了:


PostThread:如果使用事件處理函式指定了執行緒模型為PostThread,那麼該事件在哪個執行緒釋出出來的,事件處理函式就會在這個執行緒中執行,也就是說釋出事件和接收事件在同一個執行緒。線上程模型為PostThread的事件處理函式中儘量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起ANR。
MainThread:如果使用事件處理函式指定了執行緒模型為MainThread,那麼不論事件是在哪個執行緒中釋出出來的,該事件處理函式都會在UI執行緒中執行。該方法可以用來更新UI,但是不能處理耗時操作。
BackgroundThread:如果使用事件處理函式指定了執行緒模型為BackgroundThread,那麼如果事件是在UI執行緒中釋出出來的,那麼該事件處理函式就會在新的執行緒中執行,如果事件本來就是子執行緒中釋出出來的,那麼該事件處理函式直接在釋出事件的執行緒中執行。在此事件處理函式中禁止進行UI更新操作。
Async:如果使用事件處理函式指定了執行緒模型為Async,那麼無論事件在哪個執行緒釋出,該事件處理函式都會在新建的子執行緒中執行。同樣,此事件處理函式中禁止進行UI更新操作。

三. unregister


OK, 最後的 unregister 就不用多說了,基本就是將subscribe 從list 裡移除 從而移除訂閱者和訂閱方法的這麼一個過程。

四. 關於sticky 的一些注意事項

總結來說呢,如果一個事件是sticky的,那麼可以允許該事件先被post,再被register,而非sticky 事件是不可以的哈。

舉個例子,在 A裡 register 了 event,並寫好了 eventA 的接收函式 onEventA(),標明 sticky = true or false,現在A跳轉到了B,在B裡post 了 eventA,然後back 會跳A,正常情況下onEventA()是能夠接收到 eventA的post的,但在特殊情況下,A跳轉完成後由於記憶體不足,被回收,這時候A 裡的 event 會被 unregister,如果eventA sticky= true,B回退A時,A 會再次 register event,因為eventA sticky= true ,所以在register過程中會 post,所以 B 中的onEventA()會收到 eventA(其實這個eventA 已然不是 B post 的了,而是A 在 register event 時 post 的);如果eventA sticky= false,則這種情況下的回退,A中的onEventA() 是收不到 B post 來的 eventA的。。

好繞啊,不過看了原始碼其實挺好懂的,所以在用的時候一定注意 event的執行緒模型選擇以及 sticky 值,也不能把sticky全置為 true,畢竟sticky 事件需要用list儲存,存太多必然消耗效能。

相關推薦

Android學習筆記—— EventBus 原始碼解析

最近專案裡用到的EventBus 更新到了 3.0,學習了一下EventBus 3.0 的原始碼,發現3.0版本較之前版本變化還是相對較大的,無論從效能上,還是使用流程上。恰好組內分享輪到我,所以就做

android EventBus原始碼解析

尊重原創,轉載請標明出處   http://blog.csdn.net/abcdef314159 eventBus3.1.1 eventBus主要用於資料之間的傳遞,使用也非常簡單,就幾個主要的方法,一個是register和unregister,這兩個要成對出現

Android學習筆記——Android系統整體架構與原始碼目錄

首先要感謝**@劉望舒**大神的部落格,讓我們這些渣渣有途徑更快速地接觸到Android系統層的內容。 本篇部落格主要介紹了Android系統的整體架構及原始碼的目錄結構。 Android系統架構 Android的系統架構可以分為五層,分別是 應用層、應用框架

Android學習筆記2:Hello World程式解析

《第一行程式碼——Android》郭霖著 Android Studio入門到精通 Android Studio與Eclipse的一些不同 Android Studio是基於IDEA的,IDEA 全稱IntelliJ IDEA,是java語言開發的整合環境。IDEA

Android FM模組學習之四原始碼解析(三)

     由於最近一直忙專案,沒有時間來更新文件,今天抽空來寫一點,希望大家可以學習使用!      這一章當然還是來分析FM模組的原始碼。FmReceiver.java publicFmReceiver(String devicePath,FmRxEvCallbacks

android學習筆記之通過java原始碼設定EditText不可編輯狀態

EditText在xml佈局檔案中,可以通過editable設定是否能夠編輯,但在實際使用中,我們可能需要動態進行設定能否進行編輯。 android:editable="true"在java原始碼中,需要通過setKeyListener(null)方法進行動態設定。 et

Android學習筆記(十四)——在執行時新增碎片(附原始碼

在執行時新增碎片 將UI分割為多個可配置的部分是碎片的優勢之一,但其真正強大之處在於可在執行時動態地把它們新增到活動中。 1、使用上一篇建立的Fragments專案,在main.xml檔案中註釋掉兩個<fragment>元素; 2、在FragmentA

Android FM模組學習之四原始碼解析(四)

     我今天想分享的是FM模組的儲存方法,即FmSharedPreferences.java FmSharedPreferences(Context context)在構造方法中載入Load()方法, public void  Load(){       Log.d(

Android FM模組學習之四原始碼解析(一)

  前一章我們瞭解了FM手動調頻,接下來我們要分析FM模組用到的原始碼。此原始碼是基於高通平臺的,別的平臺都大同小異,只不過是平臺自己作了些小改動而已。    首先要看的當然是主activity,

Android學習筆記(三八):資源resource(上)、XML解析(XmlPullParser)

resource是java原始碼之外的靜態資訊。例如layout。resource作為檔案存放在res/目錄下面,除了res/raw/外,Android會自動解析,例如layout檔案,我們不需要自己去解析XML封裝。我們之前用過res/layout/,以及res/anim

Pro Android學習筆記(一三七):Home Screen Widgets(3):配置Activity

map onclick widgets info xtra ces extends height appwidget 文章轉載僅僅能用於非商業性質,且不能帶有虛擬貨幣、積分、註冊等附加條件。轉載須註明出處http://blog.csdn.net/flowingfly

Android學習筆記-TextView(文本框)(二)

com ddc tel spanned extra pac 全部 con 平時 文章參考自:http://www.runoob.com/w3cnote/android-tutorial-textview.html 2.4 使用autoLink屬性識別鏈接類型 當文字中出

Android學習筆記-ImageView(圖像視圖)

尺寸 map 顯示 htm 通過 加載 內容 github bit 原文來自:http://www.runoob.com/w3cnote/android-tutorial-imageview.html 本節引言: 本節介紹的UI基礎控件是:ImageView(圖像視圖)

Android學習筆記-繪制圓形ImageView實例

eight font private cte class get wid actor oid 現在很多的APP都很喜歡圓形的頭像,這裏就簡單的寫個圓形的ImageView~ 第三方圓形ImageView控件: RoundedImageView CircleImageView

Pro Android學習筆記 ActionBar(1):Home圖標區

ces tom 新的 方便 find rac vertica lba manifest ?? Pro Android學習筆記(四八):ActionBar(1):Home圖標區 2013年03月10日 ? 綜合 ? 共 3256字 ? 字號 小 中 大 ? 評論關閉

udacity android 學習筆記: lesson 4 part a

odi todo col 數據庫版本 pretty define all 大致 lec udacity android 學習筆記: lesson 4 part a 作者:幹貨店打雜的 /titer1 /Archimedes 出處:https://

Android學習筆記:超能RecyclerView組件使用總結

popu bin view設置 and col cas mda rac data 個人認為 RecyclerView組件確實值得學習並用到我們的項目中去,前面學了相關的內容。今天再補充一些相關的東東。 1,實現對RecyclerView中的數據進行加入和刪除操作。

Android 學習筆記--9妹圖片+代碼混淆+打包

文件名 打包 andro span apk 使用 背景透明 學習筆記 tro 一、Android Studio 創建.9文件 註:找一張背景透明的png圖片,將文件名改成 " xxxx.9.png " 然後放到drawable文件中,雙擊 註:有一種

Android學習筆記(36):Android的兩種事件處理方式

post gravity cal log 基於 處理方法 hang mil 重寫 Android提供了兩種事件處理的方式:基於回調的事件處理 和 基於監聽的事件處理。 我們來說的easy理解一點: (1)基於回調的事件處理就是繼承GUI組件,並重寫該組件的

android學習筆記之ImageView的scaleType屬性

有關 sni mage nds 目標 big ins 分辨率 處理 我們知道,ImageView有一個屬性叫做scaleType,它的取值一共同擁有八種,各自是:matrix,fitXY。fitStart,fitCenter。fitEnd,center,centerCr