EventBus是Android和java的发布/订阅事件总线。
事件总线是对发布-订阅模式的一种实现,它是一种集中式事件处理机制,允许不同的组件之间彼此通信,而又不需要相互依赖,达到解耦的目的。
(1)简单Android组件之间的通信,避免了Android四大组件复杂的生命周期处理;
(2)在Android四大组件间,以及线程间传递大数据时的唯一选择。因为序列化大数据进行传递时,是十分耗时缓慢的,用EventBus是最优解法;
(3)使用class传递数据,可以携带各种各样的数据,摆脱了用Bundle传递list和数组的麻烦;
(4)清晰明了的主子线程,让你的代码更为简洁;
(1)EventBus可以大量解耦项目,但是滥用它,会产生一个非常危险的后果:需要定义大量的常量或者新的实体类来区分接收者,管理EventBus的消息类别将会让你很痛苦;
(2)不要在非前台组件中使用它,因为将它使用到每一个工具类或者后台业务类,会让数据发送与接收更加复杂。别忘记了Java本身就是面对对象语言,它有接口、抽象可以实现来发送与接收数据。我们可以用各种设计模式,比如观察者模式,来更好的优化与独立自己的业务,不需要依赖EventBus;
(3)EventBus,并不是真正的解耦,不要在独立的模块里使用EventBus来分发。这个模块如果那天要直接放入另外一个项目里,你怎么解耦EventBus? 最好,还是多使用接口与Activity本身的数据传递方式。。
(1)EventBus2.x使用的是运行时注解,它采用了反射的方式对整个注册的类的所有方法进行扫描来完成注册,因而会对性能有一定影响;
(2)EventBus3.x使用的是编译时注解,Java文件会编译成.class文件,再对class文件进行打包等一系列处理。在编译成.class文件时,EventBus会使用EventBusAnnotationProcessor注解处理器读取@Subscribe()注解并解析、处理其中的信息,然后生成Java类来保存所有订阅者的订阅信息。这样就创建出了对文件或类的索引关系,并将其编入到apk中;
(3)从EventBus3.0开始使用了对象池缓存减少了创建对象的开销;
(1)定义事件
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
(2)准备订阅者
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// 这个方法将在MessageEvent被发布时被调用(在Toast的UI线程中)
@Subscribe (threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
// 这个方法将在SomeOtherEvent发布时被调用
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
doSomethingWith(event);
}
(3)发布事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
(4)学习链接
如何开始与EventBus在3个步骤
利用了subscriptionsByEventType这个重要的HashMap对象,将订阅者们,即接收事件的方法存储在这个列表,发布事件的时候在列表中查询出相对应的方法并执行。
Map, CopyOnWriteArrayList> subscriptionsByEventType;
(1)Publisher是发布者:通过post()方法将消息事件Event发布到事件总线;
(2)EventBus是事件总线: 核心模块;
(3)Subscriber是订阅者:收到事件总线发下来的消息,即onEvent方法被执行。注意参数类型必须和发布者发布的参数一致;
(1)register(Object object): 将所在类作为订阅者,框架会通过反射机制获取所有方法以及其参数,并将订阅者和订阅的方法以及其参数保存到Map中,key为Object,value为Subscription类型的ArrayList,下次从Map中获取。
(2)post(Object event):去遍历所有已经注册事件的订阅者们(即是Map中的key值),然后在根据订阅者对象找到它内部被注解方法(onEvent()),再匹配“被注解方法的参数类型”和“发布者发送的事件类型”是否是同一类型或者父类,就进行反射调用。线程切换用handler和线程池结合runnable进行切换。。
(3)postSticky(Object event): 最后还是调用的post()方法,只是多加了一个添加到粘滞Map中(Map
// 订阅者类的方法实体
public class SubscriberMethod {
/** 回调方法 */
public Method method;
/** 线程模式 */
public ThreadMode threadMode;
/** 方法中的参数 */
public Class> eventType;
/** 是否是粘滞事件 */
public final boolean sticky;
public SubscriberMethod(Method method, ThreadMode threadMode, Class> eventType, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.sticky = sticky;
}
}
// 包装了订阅者+订阅者类的方法的对象
public class Subscription {
public final Object subscriber;
public final SubscriberMethod subscriberMethod;
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
}
@Override
public boolean equals(Object other) {
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);
} else {
return false;
}
}
@Override
public int hashCode() {
return subscriber.hashCode() + subscriberMethod.eventType.hashCode();
}
}
// 包装了订阅者+订阅者类的方法的对象 + 事件对象
public class PendingPost {
public Object event;
public Subscription subscription;
public PendingPost(Object event, Subscription subscription) {
this.event = event;
this.subscription = subscription;
}
}
// 方法执行的线程
public enum ThreadMode {
/**
* 订阅者将在发布事件的同一线程中被直接调用。这是默认值。事件传递意味着开销最小,因为它完全避免了线程切换。
* 因此,对于可以在很短的时间内完成而不需要主线程的简单任务,推荐使用这种模式。使用此模式的事件处理程序必须快速返回,
* 以避免阻塞可能是主线程的发布线程。
*/
POSTING,
/**
* 订阅者将在Android的主线程(UI线程)中被调用。如果发布线程是主线程、订阅方方法将被直接调用,阻塞发布线程。
* 否则事件正在排队等待交付(非阻塞)。使用此模式的订阅者必须快速返回,以避免阻塞主线程。
*/
MAIN,
/**
* 订阅者将在后台线程中被调用。如果发布线程不是主线程,订阅方方法将在发布线程中直接调用。
* 如果提交线程是主线程,则EventBus使用单个线程后台线程,它将按顺序交付其所有事件。
* 使用此模式的订户应尝试这样做快速返回,避免阻塞后台线程。
*/
BACKGROUND
}
// 注解类,只有被注解订阅的方法才会被添加到集合中
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
/** 线程模式 */
ThreadMode threadMode() default ThreadMode.POSTING;
/** 如果为true,则post最近的粘滞事件 */
boolean sticky() default false;
}
// 判断是否是主线程,通常在Android上使用Android的主线程
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);
}
}
}
// post事件接口
interface Poster {
/**
* 为特定订阅加入要发布的事件队列
*
* @param subscription 订阅将会收到事件的订阅
* @param event 事件将会发布给订阅者.
*/
void enqueue(Subscription subscription, Object event);
}
// 主线程中post事件
public class HandlerPoster extends Handler implements Poster {
private final LinkedList queue;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper) {
super(looper);
this.eventBus = eventBus;
this.queue = new LinkedList<>();
}
public void enqueue(Subscription subscription, Object event) {
synchronized (this) {
PendingPost pendingPost = new PendingPost(event, subscription);
queue.offer(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
Log.e(EventBus.TAG, "Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// 再次检查,这次是同步的
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost.subscription, pendingPost.event);
rescheduled = true;
}
} finally {
handlerActive = rescheduled;
}
}
}
// 子线程中post事件
public class BackgroundPoster implements Runnable, Poster {
private final LinkedList queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new LinkedList<>();
}
public void enqueue(Subscription subscription, Object event) {
synchronized (this) {
PendingPost pendingPost = new PendingPost(event, subscription);
queue.offer(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// 再次检查,这次是同步的
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost.subscription, pendingPost.event);
}
} finally {
executorRunning = false;
}
}
}
/**
* EventBus发布/订阅事件总线
*/
public class EventBus {
public static String TAG = "Tag_EventBus";
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
private static volatile EventBus defaultInstance;
/**
* 判断是否是主线程
*/
private final MainThreadSupport mainThreadSupport;
private final Poster mainThreadPoster;
private final BackgroundPoster backgroundPoster;
/**
* 接收 订阅者+订阅者类的方法的对象 存储在这个列表中
*/
private final Map
// 定义事件
public class MessageEvent {
public String name;
public String num;
public MessageEvent(String name, String num) {
this.name = name;
this.num = num;
}
}
// EventBus发布事件页面
public class EventBusPostActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_eventbus_post);
}
/**
* 在子线程中发布事件
*/
public void postInThread(View view) {
new Thread(new Runnable() {
@Override
public void run() {
// 在子线程中发布事件
Log.d(EventBus.TAG, "子线程中发布 threadName :" + Thread.currentThread().getName());
EventBus.getDefault().post(new MessageEvent("小小", "123"));
}
}).start();
}
/**
* 在主线程中发布事件
*/
public void postInMain(View view) {
Log.d(EventBus.TAG, "主线程中发布 threadName :" + Thread.currentThread().getName());
EventBus.getDefault().post(new MessageEvent("大大","456"));
}
/**
* 发布粘性事件
*
* @param view
*/
public void postSticky(View view) {
Log.d(EventBus.TAG, "发布 postSticky threadName :" + Thread.currentThread().getName());
// 粘性事件,在发送事件之后再订阅该事件也能收到。并且,粘性事件会保存在内存中,每次进入都会去内存中查找获取最新的粘性事件,除非你手动解除注册。
EventBus.getDefault().postSticky(new MessageEvent("发布 postSticky:Hello everyone!", "789"));
}
/**
* 手动获取和删除粘性事件
*
* @param view
*/
public void removeStickyEvent(View view) {
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
if(stickyEvent != null) {
EventBus.getDefault().removeStickyEvent(stickyEvent);
}
}
/**
* 注册
*
* @param view
*/
public void register(View view) {
EventBus.getDefault().register(this);
}
/**
* 反注册
*
* @param view
*/
public void unRegister(View view) {
EventBus.getDefault().unregister(this);
}
/**
* 当MessageEvent被发布时将调用此方法
*
* 默认情况下,EventBus捕获从订阅者方法抛出的异常,并发送不强制要求处理的SubscriberExceptionEvent。
* Caused by: EventBusException: Subscriber class ...EventBusActivity and its super classes have no public methods with the @Subscribe annotation
*
* @param event
*/
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventBus(MessageEvent event) {
Log.e(EventBus.TAG,"onEventBus + 接收到EventBus事件:" + event.name);
}
/**
* EventBus 是为已经存在的activity传递消息,而且订阅者必须要注册且不能被注销了,
* 如果你在onStop里面注销了,栈中虽然有这个activity,但是EventBus并没有被注册,所以也接收不到消息,
*/
// @Override
// public void onStop() {
// EventBus.getDefault().unregister(this);
// super.onStop();
// }
@Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
D/Tag_EventBus: 主线程中发布 threadName :main
D/Tag_EventBus: onEvent: com.example.rxjava_example.MessageEvent@48b101b
D/Tag_EventBus: onEvent threadName :main
D/Tag_EventBus: onMessageEvent: com.example.rxjava_example.MessageEvent@48b101b
D/Tag_EventBus: onMessageEvent threadName :pool-1-thread-1
D/Tag_EventBus: 发布 postSticky threadName :main
E/Tag_EventBus: onEventBus + 接收到EventBus事件:发布 postSticky:Hello everyone!
D/Tag_EventBus: onEvent: com.example.rxjava_example.MessageEvent@a595ef6
D/Tag_EventBus: onEvent threadName :main
D/Tag_EventBus: onMessageEvent: com.example.rxjava_example.MessageEvent@a595ef6
D/Tag_EventBus: onMessageEvent threadName :pool-1-thread-1
(1)EventBus.getDefault():通过单例模式获得EventBus对象
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;
}
(2)通过构建EventBusBuilder来设置参数
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
// 保存事件参数类和Subscription List的Map
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
// 保存注册对象和事件参数类
private final Map>> typesBySubscriber;
// 粘性事件
private final Map, Object> stickyEvents;
public class EventBusBuilder {
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
// 异常的设置
boolean logSubscriberExceptions = true;
boolean logNoSubscriberMessages = true;
boolean sendSubscriberExceptionEvent = true;
boolean sendNoSubscriberEvent = true;
boolean throwSubscriberException;
boolean eventInheritance = true;
// 是否忽略生成的Index,默认为false,不忽略
boolean ignoreGeneratedIndex;
boolean strictMethodVerification;
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
List> skipMethodVerificationForClasses;
List subscriberInfoIndexes;
EventBusBuilder() {
}
}
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
// 主线程发送器
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
// 后台线程发送器
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;
}
EventBus初始化的步骤,直观上看用到单例模式和Builder模式,将构造参数给分离了出来,实际上还用到了策略模式,其中Builder中有些参数用于代码执行的策略,就说,你传的参数不一样,我执行的方式不一样,像ignoreGeneratedIndex作用就是让EventBus如何查找出订阅方法的策略。
(3)最重要的是一些缓存对象:
subscriptionsByEventType : 内部是一个Map集合,可以根据 EventType 查找订阅事件;
typesBySubscriber : 根据我们的订阅对象找到 EventType;
stickyEvents : 粘滞事件的缓存;
事件投递者 : mainThreadPoster, backgroundPoster, asyncPoster根据订阅注解ThreadMode去选择不同的投递者,不同投递者投递事件,接收函数会执行在不同的线程中;
subscriberMethodFinder :查找方法用的,内部维护了一个订阅方法的集合。
// Eventbus.java:
public void register(Object subscriber) {
// 获得注册对象的class
Class> subscriberClass = subscriber.getClass();
// 5.2.1 查找订阅者被订阅的方法
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 5.2.2 订阅
subscribe(subscriber, subscriberMethod);
}
}
}
当我们调用register(this)的时候就把订阅者给传了进来,主要就两个步骤:第一个findSubscriberMethods()找出一个SubscriberMethod的集合,然后就遍历 SubscriberMethod的集合去订阅事件,我们先看**findSubscriberMethods()**里面到底做了什么,返回的是什么?
// SubscriberMethodFinder.java:
List findSubscriberMethods(Class> subscriberClass) {
// 5.2.1.1 从方法缓存中查找
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
// 找到直接返回
if (subscriberMethods != null) {
return subscriberMethods;
}
// 是否忽略生成的Index(高级用法会通过编译时注解生成,这里不会)
// ignoreGeneratedIndex默认为false,进入下面的代码
if (ignoreGeneratedIndex) {
// 5.2.1.3 通过反射获取方法
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 5.2.1.2 通过subscriberInfo获取方法
subscriberMethods = findUsingInfo(subscriberClass);
}
// 如果没有找到方法,抛出异常(常见的这个异常,没有@Subscribe方法)
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
// 5.2.1.4 找到订阅方法后放入缓存,以免下次继续重新查找
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
// SubscriberMethodFinder.java
private List findUsingReflection(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 5.2.1.2(3)第3步,进入**findUsingReflectionInSingleClass通过反射来调用**
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
findUsingReflectionInSingleClass(findState)的分析请看:5.2.1.2(3)第3步,进入findUsingReflectionInSingleClass通过反射来调用。
// SubscriberMethodFinder.java:
private List findUsingInfo(Class> subscriberClass) {
// 第1步:从池中或创建或使用
FindState findState = prepareFindState();
// 初始化
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 第2步:调用getSubscriberInfo查找是否有添加的SubscriberInfoIndex,这个是需要添加编译器支持,
// 并且在编译器自动生成,需要手动添加的,默认是没有添加的
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 第3步:如果没有找到,通过反射来查找
findUsingReflectionInSingleClass(findState);
}
// 获得其父类
findState.moveToSuperclass();
}
// 第4步:获得方法并释放FindState对象
return getMethodsAndRelease(findState);
}
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
// SubscriberMethodFinder.java:
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 1、获得类的方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
// 2、如果方法的修饰符是public并且不是 Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 获得参数类型数组
Class>[] parameterTypes = method.getParameterTypes();
// 如果参数是一个
if (parameterTypes.length == 1) {
// 判断该方法是否被Subscribe注解修饰
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
// 如果还有Subscribe注解,则将参数类型
if (subscribeAnnotation != null) {
Class> eventType = parameterTypes[0];
// 3、检验下是否之前已经添加了SubscriberMethod对象
if (findState.checkAdd(method, eventType)) {
// 返回false,说明其父类也有这个方法
// 返回true,说明其父类没有这个方法,findState.subscriberMethods中添加SubscriberMethod对象
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
// 抛出参数过多的异常
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
// 抛出方法修饰符不正确异常
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
(1)反射的3个步骤:
1、获得类的方法;
2、遍历类,并且检查:
(1)检查方法修饰符是不是public;
(2)检查参数数量是不是等于1;
(3)检查方法是否还有Subscribe注解;
三个条件都满足的话,则需要检查方法和参数类型是否已经存在,是否此方法需要添加threadMode;
3、根据检查结果来判断是否添加SubscriberMethod对象;
(2)添加订阅方法前有个检查checkAdd方法:
// SubscriberMethodFinder.java:
boolean checkAdd(Method method, Class> eventType) {
// 分两步检查:
// 1. 检查参数类型是不是已经存在
// 2. 通过方法签名(可以说是名称拼接)来判断
Object existing = anyMethodByEventType.put(eventType, method);
// 不存在接收该参数类型的方法
if (existing == null) {
return true;
} else {
// 存在接收该参数类型的方法,这里应该比较少见。应该就是不同的方法但是都有相同的参数
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
// SubscriberMethodFinder.java:
private boolean checkAddWithMethodSignature(Method method, Class> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
// 将方法名和事件类型当作key,来保存方法
String methodKey = methodKeyBuilder.toString();
Class> methodClass = method.getDeclaringClass();
Class> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
// 如果我们保存的是父类,就返回 true
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// 如果是子类,就将传来的方法保存起来,返回 false
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
这里又做了一个优化,将方法名和事件类型当作key,来保存方法,将传来的方法类型和我们签名的保存的比较;如果我们保存的是父类,就返回true,如果是子类,就将传来的方法保存起来,返回false。这样做的意图是:如果有父类的方法了,就没有必要添加子类的方法了,因为继承会执行到的。
EventBus提供了一个EventBusAnnotationProcessor注解处理器来在编译期通过读取@Subscribe()注解并解析,处理其中所包含的信息,然后生成java类来保存所有订阅者关于订阅的信息,这样就比在运行时使用反射来获得这些订阅者的信息速度要快。
private SubscriberInfo getSubscriberInfo(FindState findState) {
// 查找FindState的缓存是否有订阅信息,有则直接返回
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
// 从subscriberInfoIndexes中查找订阅信息(EventBusBuilder的subscriberInfoIndexes)
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
(1)在项目的app的build.gradle中添加如下配置:
android {
defaultConfig {
// EventBus processor
javaCompileOptions {
// 注解处理器参数配置
annotationProcessorOptions {
// 配置参数名和值
arguments = [eventBusIndex: 'com.seniorlibs.thirdlib.MyEventBusIndex']
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// EventBus
api 'org.greenrobot:eventbus:3.2.0'
// EventBus processor
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.2.0'
}
(2)然后rebulid,在\build\generated\source\apt\com.seniorlibs.thirdlib\下看到通过注解分析生成的索引类MyEventBusIndex
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(com.seniorlibs.thirdlib.eventbus.EventBusActivity.class, true,
new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onMessageEvent", com.seniorlibs.thirdlib.eventbus.MessageEvent.class,
ThreadMode.MAIN, 0, true),
}));
}
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
}
(3)在Application中通过EventBus初始化,将这个类给传进去:
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus().register(this);
(4)MyEventBusIndex在初始化时,直接会将订阅者相关信息缓存在Map中,并实现了SubscriberInfoIndex接口,在实现方法getSubscriberInfo中根据订阅类返回对应的订阅者信息。在编译过程中就已经找到我们的订阅信息了,不会在运行期做任何事情,所以这个效率是非常高的。
// SubscriberMethodFinder.java:
private List getMethodsAndRelease(FindState findState) {
// 创建List并返回
List subscriberMethods = new ArrayList<>(findState.subscriberMethods);
// 池回收并将给池中的为空的位置赋值,方便findState下次使用,不需要
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
从这里,我们就知道作者设计FindState池的初心了,解析完了之后,将订阅方法赋给List集合,再回收FindState,继续接收解析,内存没有半点浪费。
// EventBus.java
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 参数类型
Class> eventType = subscriberMethod.eventType;
// 根据订阅者和订阅方法构造一个订阅事件
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// subscriptionsByEventType是根据eventType去查找subscriptions集合
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
// 看看缓存中有没有,没有则放进缓存
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 已经存在的话,抛出异常
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
}
}
// 遍历订阅事件,找到比subscriptions中订阅事件大的优先级,然后插入。就可以根据优先级依次投递事件了
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// typesBySubscriber是根据订阅者去查找EventType的缓存,并保存起来。为的是unregister(this),根据this去解绑事件
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
// 添加新的参数类型
subscribedEvents.add(eventType);
// 如果是粘性,就立刻处理
if (subscriberMethod.sticky) {
// 构造是默认为true
if (eventInheritance) {
// EventType的子类也应该考虑
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, Object> entry : entries) {
Class> candidateEventType = entry.getKey();
// 参数类型是存储的父类或者相同
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
// 如果有值的话发送事件
// 意味着如果粘性事件的参数类型存在,并且对应的值也存在的话将发送事件
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
订阅其实里面就做了两件事:
(1)第1件事:遍历订阅方法和订阅者,订阅者和订阅方法的参数类型保存起来,封装到subscriptionsByEventType和typesBySubscriber,至于这两个对象是干什么的呢?subscriptionsByEventType是我们投递订阅事件的时候,就是根据订阅方法参数类型EventType找到订阅事件subscriberMethod,从而去分发处理事件;typesBySubscriber是在调用unregister(this) 的时候,根据订阅者subscriber找到订阅方法参数类型EventType,又根据EventType找到订阅事件,从而解绑。
(2)第2件事:如果是粘性事件的话,就立马投递并执行。
public void post(Object event) {
// 使用ThreadLocal来确保每个线程都维护了一个投递状态PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
// 获取事件队列
List eventQueue = postingState.eventQueue;
// 将最新的事件添加到队尾
eventQueue.add(event);
// 如果当前没有进行中的事件
if (!postingState.isPosting) {
// 设置当前线程是否为主线程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
// 设置正在发送状态
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
// PostingThreadState是维护了投递的状态,最后循环投递,直到PostingThreadState中的EventQueue为空
while (!eventQueue.isEmpty()) {
// 发送事件
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
调用post(Object object) 的方法的时候就执行了上面的代码,PostingThreadState是维护了投递的状态,最后循环投递,直到 PostingThreadState中的EventQueue为空。那么代码最终执行到postToSubscription(),根据ThreadMode去处理事件,通过策略模式实现线程模式:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
// 根据订阅方法的threadMode来判断如何执行
switch (subscription.subscriberMethod.threadMode) {
// 默认,在哪个线程发送在哪个线程执行
case POSTING:
invokeSubscriber(subscription, event);
break;
// 最终执行在主线程中
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
// 后台线程
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
// 异步线程
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
当线程模式是主线程的时候,意味着需要执行的代码在主线程中操作,就是通过反射,直接运行订阅的方法;如果不是主线程,需要mainThreadPoster将订阅事件入队列。一起看看mainThreadPoster的工作原理:
// HandlerPoster.java
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) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
其实在EventBus初始化的时候,mainThreadPoster就已经获取主线程的Looper了,就是用到了Android的消息处理机制:Looper、Handler,至于消息队列是自己维护的一个单向的链表。每次向Andorid的主线程Looper投递一个空消息,然后在 HandlerMessage()方法里面从自己维护的队列中取出PendingPost 进行处理。而PendingPost中维护的是订阅事件,EventType 和下一个PendingPost的地址:
final class PendingPost {
private final static List pendingPostPool = new ArrayList();
Object event;
Subscription subscription;
PendingPost next;
}
// BackgroundPoster.java:
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
// 入队操作
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
// 这里用到了线程池去执行
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
// 出队,执行队列中所有的事件
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// 再次检测,如果还没有则执行结束
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
// 存在PendingPost对象,调用EventBus去执行订阅者订阅的方法
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
// executorService的默认值是下面的线程池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue());
}
BackgroundPoster这里面维护了一个队列,如果此发送器正在执行,则将此次事件的PendingPost(将要发送的事件)对象加入队列的尾部,在子线程的run方法中通过PendingPostQueue.poll()方法获得第一个PendingPost对象,并且调用eventBus.invokeSubscriber(pendingPost)去执行订阅的方法。
// EventBus.java:
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
// 如果没有取消注册,这个变量是volatile修饰,每次都会取最新值
// 调用invokeSubscriber方法执行订阅的方法
invokeSubscriber(subscription, event);
}
}
void invokeSubscriber(Subscription subscription, Object event) {
try {
// 执行订阅者订阅的方法,参数是event
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
public synchronized void unregister(Object subscriber) {
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
**反注册就是通过EventBus中typesBySubscriber这个属性,通过订阅者subscriber去查找订阅事件eventType,然后去一一解绑的。**当然,反注册主要是为了提高效率的,不然订阅的事件太多,非常影响性能。
看订阅中的最后一段代码呢?5.2.2 需要订阅的方法已经找到,接下来将方法订阅-subscribe()
// EventBus.java
// 如果是粘性,就立刻处理
if (subscriberMethod.sticky) {
// 构造是默认为true
if (eventInheritance) {
// EventType的子类也应该考虑
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, Object> entry : entries) {
Class> candidateEventType = entry.getKey();
// 参数类型是存储的父类或者相同
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
// 如果有值的话发送事件
// 意味着如果粘性事件的参数类型存在,并且对应的值也存在的话将发送事件
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}
// 发布粘性事件
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
post(event);
}
// 手动获取和删除粘性事件
public boolean removeStickyEvent(Object event) {
synchronized (stickyEvents) {
Class> eventType = event.getClass();
Object existingEvent = stickyEvents.get(eventType);
if (event.equals(existingEvent)) {
stickyEvents.remove(eventType);
return true;
} else {
return false;
}
}
}
Android——EventBus源码分析
EventBus 3.0源码解析
Android主流三方库源码分析(九、深入理解EventBus源码)
EventBus3.0使用及源码分析(包含UML图)
EventBus3.0解析之注解处理器分析
GitHub-EventBus仓库