这可能是最详细的 EventBus 源码分析01 - EventBus 对象的创建

这可能是最详细的 EventBus 源码分析01 - EventBus 对象的创建
这可能是最详细的 EventBus 源码分析02 - EventBus 的注册(上篇)
这可能是最详细的 EventBus 源码分析03 - EventBus 的注册(下篇)
这可能是最详细的 EventBus 源码分析04 - 事件的发送与执行
这可能是最详细的 EventBus 源码分析05 - Subscriber Index

相信大家对 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);

    //如果未使用自定义索引类, 初始化的时候 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. 关系如下图显示

subscriptionsByEventType

这个 map 的目的是为了在发送 Event事件的时候, 总能根据此 map 找到所有的订阅记录,再根据订阅记录中的订阅方法包装类处理此事件的线程模型, 将此事件分发到对应的线程, 利用反射, 调用订阅者对此事件的事件处理方法,完成事件的发布与处理.


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

typesBySubscriber 的声明为 private final Map<Object, List<Class<?>>> typesBySubscriber

以订阅者为 key, 以订阅者中订阅的所有 Event 事件类型列表为 value

typesBySubscriber

当注册与反注册事件的时候, 都会对这个 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, 而变量 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 对象算是创建完成了.
后面将会接着分析注册/解绑, 发送事件等等.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。