這可能是最詳細的 EventBus 源碼分析01 - EventBus 對象的創建
這可能是最詳細的 EventBus 源碼分析02 - EventBus 的註冊(上篇)
這可能是最詳細的 EventBus 源碼分析03 - EventBus 的註冊(下篇)
這可能是最詳細的 EventBus 源碼分析04 - 事件的發送與執行
這可能是最詳細的 EventBus 源碼分析05 - Subscriber Index
相信大家對 EventBus
都是非常熟悉了. 做 Android
開發的同學基本都使用過這個框架. 它的用法基本分爲以下幾個步驟
- 定義事件
event
. - 通過註解, 準備訂閱者.
- 訂閱者同時需要在事件總線上註冊和註銷自己.
(register, unregister)
- 發送事件.
- 任何匹配到該事件的訂閱者, 都將會接收到這個事件.
這裏就不在說明 EventBus
的具體用法了, 那麼在接下來, 將會對 EventBus
的源碼及內部原理進行學習分析.
(這裏分析的 EventBus
源碼版本爲 3.2.0
)
1. EventBus 對象的構建
在使用 EventBus
的時候, 無論是註冊/反註冊或者是發送事件都會先調用 EventBus.getDefault()
這個方法. 那麼就以這個方法爲入口來進行分析.
1.1 EventBus.getDefault()
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
這裏很清楚的看到, 這就是使用單例模式構建了一個 EventBus
對象. 那麼接着進入到 EventBus
的構造函數中.
1.2 EventBus()
public EventBus() {
this(DEFAULT_BUILDER);
}
是不是發現和我們平時寫的單例有點不同呢? 我們平時寫的單例, 構造方法一般都是 private
的. 但是這裏卻是 public
.
那麼 EventBus
有了單例後, 爲什麼還要把構造函數設置爲 public
呢 ? 是不是有特別的用意呢 ?
原來啊,
EventBus
這樣設計是有原因的. 我們要知道EventBus
在我們的整個代碼當中, 並不是僅僅只有一條總線的. 還會有其他的EventBus
總線. 那麼我們的訂閱者, 就可以註冊到不同的EventBus
下. 然後通過不同的EventBus
來發送數據給訂閱者.而我們需要注意的是, 不同的
EventBus
發送的數據, 是相互隔離的. 訂閱者只會收到註冊到該線程上的數據.
接着看. 構造函數中又調用了 this(DEFAULT_BUILDER)
, 點擊 DEFAULT_BUILDER
可以知道就是 EventBusBuilder
.
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
看到這裏可以猜到 EventBus
最終還是通過構建者模式來進行對象的創建的. 下面跟進到 EventBus(EventBusBuilder builder)
構造方法中.
1.3 EventBus(EventBusBuilder builder)
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
//分析 1
subscriptionsByEventType = new HashMap<>();
//分析 2
typesBySubscriber = new HashMap<>();
//黏性事件: 發送事件之後, 再訂閱該事件也能收到該事件,跟黏性廣播類似. 使用支持併發的 ConcurrentHashMap 創建
stickyEvents = new ConcurrentHashMap<>();
//分析 3
//創建實現了 MainThreadSupport 接口的內部類 AndroidHandlerMainThreadSupport, 並傳入MainLooper.
mainThreadSupport = builder.getMainThreadSupport();
// 分析 4
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
//創建後臺處理的 poster
backgroundPoster = new BackgroundPoster(this);
//創建異步處理的 poster
asyncPoster = new AsyncPoster(this);
//如果未使用自定義索引類, 初始化的時候 builder.subscriberInfoIndexes 爲 null. 所以 indexCount 爲 0
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
//若未使用自定義索引類, subscriberInfoIndexes 爲 null. 所以初始化subscriberMethodFinder 對象時傳入參數爲 null, false, false.
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//調用事件處理方法的時候, 發生異常後是否打印異常信息日誌, 默認爲 true
logSubscriberExceptions = builder.logSubscriberExceptions;
//當沒有訂閱者訂閱當前 Event 事件的時候, 是否需要打印日誌, 默認爲 true
logNoSubscriberMessages = builder.logNoSubscriberMessages;
//當調用事件處理方法的時候如果出現異常, 是否需要發送 SubscriberExceptionEvent 事件, 默認爲 true
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
//當沒有事件處理方法時, 是否需要發送 NoSubscriberEvent 事件, 默認爲 true
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
//是否需要拋出 SubscriberException 異常, 默認爲 false
throwSubscriberException = builder.throwSubscriberException;
//與Event 有繼承關係的是否都需要發送, , 默認爲 true
eventInheritance = builder.eventInheritance;
//構建線程池.默認構建的爲 Executors.newCachedThreadPool();
executorService = builder.executorService;
}
由於屬性字段太多, 這裏只挑了幾個比較重要, 並且有代表性的來分析一下.
- 分析 1
subscriptionsByEventType = new HashMap<>()
subscriptionsByEventType
的聲明爲private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
.
以當前 Event
事件爲 key
, 以 CopyOnWriteArrayList<Subscription>
列表爲 value
. 關係如下圖顯示
這個 map
的目的是爲了在發送 Event
事件的時候, 總能根據此 map
找到所有的訂閱記錄,再根據訂閱記錄中的訂閱方法包裝類處理此事件的線程模型, 將此事件分發到對應的線程, 利用反射, 調用訂閱者對此事件的事件處理方法,完成事件的發佈與處理.
- 分析 2
typesBySubscriber = new HashMap<>()
typesBySubscriber
的聲明爲private final Map<Object, List<Class<?>>> typesBySubscriber
以訂閱者爲 key
, 以訂閱者中訂閱的所有 Event
事件類型列表爲 value
當註冊與反註冊事件的時候, 都會對這個 typesBySubscriber
進行操作
上面兩個 map
的數據都是各個線程都可以訪問的,因此訪問的時候要對這兩個 map
加鎖.
- 分析 3
mainThreadSupport = builder.getMainThreadSupport()
調用了EventBusBuilder.getMainThreadSupport()
方法, 現在進去看一下這個方法內部做了什麼.
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (AndroidLogger.isAndroidLogAvailable()) {
Object looperOrNull = getAndroidMainLooperOrNull();
return looperOrNull == null ? null : new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
static Object getAndroidMainLooperOrNull() {
try {
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
看到
getMainThreadSupport
方法返回的是MainThreadSupport
, 而變量mainThreadSupport
在EventBusBuilder
並沒有找到給它賦值的地方. 那麼就是爲null
. 執行else if
方法.AndroidLogger.isAndroidLogAvailable()
這裏返回的爲true
, 接着調用getAndroidMainLooperOrNull ()
方法獲取到主線程的looper
. 接着創建實現了MainThreadSupport
接口的內部類AndroidHandlerMainThreadSupport
傳入主線程looper
並返回.
接着進入到 MainThreadSupport.AndroidHandlerMainThreadSupport
看他的構造方法.
public interface MainThreadSupport {
boolean isMainThread();
Poster createPoster(EventBus eventBus);
class AndroidHandlerMainThreadSupport implements MainThreadSupport {
private final Looper looper;
public AndroidHandlerMainThreadSupport(Looper looper) {
this.looper = looper;
}
@Override
public boolean isMainThread() {
return looper == Looper.myLooper();
}
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
}
}
看到構造方法內只是將上面傳入的主線程
looper
保存下來.
那麼分析 3 的流程就走完了, 總的來說就是創建實現了 MainThreadSupport
接口的內部類 AndroidHandlerMainThreadSupport
, 並在 AndroidHandlerMainThreadSupport
中保存了主線程的 looper
- 分析 4
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
創建在主線程處理的 poster
拿到剛纔創建的AndroidHandlerMainThreadSupport
對象調用它的createPoster (EventBus eventbus)
方法. 並傳入當前Event
事件.
在上面貼出來的AndroidHandlerMainThreadSupport
類中的createPoster
方法中看到就是new
了一個HandlerPoster
對象, 並傳入當前Event
事件與主線程looper
, 以及一個數值 10.
接着進入到 HandlerPoster
看一下, 都初始化了什麼.
public class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
...
}
@Override
public void handleMessage(Message msg) {
...
}
}
看到 HandlerPoster
繼承自 Handler
重寫了 handleMessage
方法來處理 Event
事件, 同時實現了 Poster
接口的 enqueue
方法將 Event
事件入隊. 這裏只看構造方法, 這兩個方法後面會有分析到.
在構造方法內, 看到將我們傳入進來
Event
事件與主線程的Looper
以及那個數字 10 都賦值給了自身的變量.
private final PendingPostQueue queue
: 存放要執行的Event
事件的一個隊列. 是一個雙向鏈表.後面會有分析.
private final int maxMillisInsideHandleMessage
: 判斷任務執行的最大時間, 大於這個時間表示超時.
private final EventBus eventBus
: 當前的Event
事件
private boolean handlerActive
: 標識當前Handler
是否是活動狀態.
那麼到這裏在分析 4 中, 就完成了主線程 mainThreadPoster
的創建.
backgroundPoster
後臺處理的 Poster
與 asyncPoster
異步處理的 Poster
與之類似, 不同的是, 他們沒有繼承 Handler
, 而是實現了 Runnable
接口. 這裏就不再對這兩個類進行分析.
剩下的在構造函數裏都說明了含義, 就不再一一查看分析了. 到這裏一個 EventBus
對象算是創建完成了.
後面將會接着分析註冊/解綁, 發送事件等等.