EventBus 源碼的閱讀01 - EventBus 對象的創建

相信大家對 EventBus 都是非常熟悉了. 做 Android 開發的同學基本都使用過這個框架. 它的用法基本分爲以下幾個步驟

  1. 定義事件 event.
  2. 通過註解, 準備訂閱者.
  3. 訂閱者同時需要在事件總線上註冊和註銷自己. (register, unregister)
  4. 發送事件.
  5. 任何匹配到該事件的訂閱者, 都將會接收到這個事件.

這裏就不在說明 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);

    //表示 Event 生成的索引, 初始化的時候 builder.subscriberInfoIndexes 爲 null. 所以 indexCount 爲 0
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    //創建尋找添加了 @Subscribe註解方法的功能類對象, 初始化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<>()

當發送 Event事件的時候, 可以通過 subscriptionsByEventType 找到對應的訂閱者.
subscriptionsByEventType 的聲明爲 private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType.
以當前 Event 事件爲 key, 也就是消息處理方法的參數的 Class
CopyOnWriteArrayList<Subscription> 列表爲 value. 也就是所有的訂閱此事件的訂閱者列表.
Subscription 對象中又包含了兩個屬性, 一個是包含了這個 Event 事件的 subscriber 訂閱者(反射執行對象),一個是 SubscriberMethod 註解方法的所有屬性參數值.


  • 分析 2 typesBySubscriber = new HashMap<>()

當註冊與反註冊事件的時候, 都會對這個 typesBySubscriber 進行操作
typesBySubscriber 的聲明爲 private final Map<Object, List<Class<?>>> typesBySubscriber
以訂閱者爲 key
以訂閱者中訂閱的所有 Event 事的件列表爲 value


上面兩個 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, 而變量 mainThreadSupportEventBusBuilder 並沒有找到給它賦值的地方. 那麼就是爲 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 後臺處理的 PosterasyncPoster異步處理的 Poster 與之類似, 不同的是, 他們沒有繼承 Handler, 而是實現了 Runnable 接口. 這裏就不再對這兩個類進行分析.


剩下的在構造函數裏都說明了含義, 就不再一一查看分析了. 到這裏一個 EventBus 對象算是創建完成了.
後面將會接着分析註冊/解綁, 發送事件等等.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章