EventBus 3 全解
[TOC]
使用
一个基于观察者模式的事件发布/订阅框架. 用于模块间通信和解耦, 使用方便,性能高.
基本使用
1. gradle导入依赖库
implementation 'org.greenrobot:eventbus:3.1.1'
2. 定义事件类
public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } }
3. 标记订阅方法. 当自定义事件发布后,此方法会被调用.
// This method will be called when a MessageEvent is posted (in the UI thread for Toast) @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show(); } // This method will be called when a SomeOtherEvent is posted @Subscribe public void handleSomethingElse(SomeOtherEvent event) { doSomethingWith(event); }
3.1 注册
@Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); }
3.2 注销
@Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); }
4. 发送事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
5. 混淆
-keepattributes *Annotation* -keepclassmembers class * { @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } # Only required if you use AsyncExecutor -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { <init>(java.lang.Throwable); }
Android平台最佳实践
使用Subscriber Index
, 在编译时为注册类和订阅构建了一个索引, 这样不必在运行时通过反射寻找订阅方法了. 对比入下图:

生成索引, gradle
配置如下:
1. 借助AnnotationProcessor
android { defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ] } } } } dependencies { implementation 'org.greenrobot:eventbus:3.1.1' annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1' }
2. 如果使用kotlin
, 使用kapt
替代annotationProcessor
apply plugin: 'kotlin-kapt' // ensure kapt plugin is applied dependencies { implementation 'org.greenrobot:eventbus:3.1.1' kapt 'org.greenrobot:eventbus-annotation-processor:3.1.1' } kapt { arguments { arg('eventBusIndex', 'com.example.myapp.MyEventBusIndex') } }
3. 如果gradle
版本小于2.2
, 可以使用android-apt
buildscript { dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } apply plugin: 'com.neenbedankt.android-apt' dependencies { compile 'org.greenrobot:eventbus:3.1.1' apt 'org.greenrobot:eventbus-annotation-processor:3.1.1' } apt { arguments { eventBusIndex "com.example.myapp.MyEventBusIndex" } }
> 截止2019年9月20日, gradle
配置用第一种就可以, 如果有特殊情况, 参考2, 3. 编译成功后, 会在如下目录生成.\app\build\generated\source\apt\debug\com\example\myapp\MyEventBusIndex.java
, 如果没报错, 也没生成, 删掉build
文件夹, 再来一次.
使用索引
方式一 :
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
方式二 :
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus(); // Now the default instance uses the given index. Use it like this: EventBus eventBus = EventBus.getDefault();
索引库
如果项目的依赖库中使用了索引, 可以添加多个索引:
EventBus eventBus = EventBus.builder() .addIndex(new MyEventBusAppIndex()) .addIndex(new MyEventBusLibIndex()).build();
原理
流程图
注册
把事件和订阅者对应起来, 一个事件可以有多个订阅者, 一个订阅者可以订阅多个事件.

发送事件
根据事件, 找到订阅者,并执行订阅者对应的方法.

注销
注销是移除订阅的操作.
根据注册的步骤可知:
typesBySubscriber = HashMap<订阅者, list<事件>> subscriptionsByEventType = HashMap<事件, list<订阅者>>
有这样两个变量维持所有的事件和订阅者的对应关系, 所以循环找到传入的订阅者, 调用Map.remove()
.
设计模式
单例
一个Double Check
:
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
构建者
EventBus(EventBusBuilder builder) { logger = builder.getLogger(); subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; sendNoSubscriberEvent = builder.sendNoSubscriberEvent; throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; }
观察者
不多说了.看上面原理图.
数据结构
ThreadLocal
问题
不支持跨进程
事件环路
把接收事件专门封装成一个子模块,同时考虑避免出现事件环路。
事件满天飞,维护困难
使用RxJava
这样就可以使用RxBus
了 :D
liveData
好东西, 和Android
组件的生命周期紧密联系, 不需要手动处理生命周期, 因此不会造成内存泄露.
说实话整个Android Architecture Components
都挺不错的, 就是出来的略晚了一些. 和现在流行的主流框架有些相持, 假以时日, 会越来越流行的.