EventBus概述
一、定义
EventBus 主要用于Android组件之间、组件与后台线程之间通信,是一个事件发布/订阅的轻量级开源库
GitHub 百科
二、使用
- 1、定义事件
/**Events are POJO (plain old Java object) without any specific requirements*/
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
- 2、订阅者注册并订阅事件
public class TestActivity extends Activity {
//订阅者注册
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
//订阅者订阅事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
//处理事件、MessageEvent事件发布后该方法将被调用
}
}
- 3、发布事件
/**
* 代码的任意位置发布MessageEvent事件后,当前所有订阅MessageEvent事件的订阅者都将收到该事件
* Post an event from any part of your code.
* All currently registered subscribers matching the event type will receive it.
*/
EventBus.getDefault().post(new MessageEvent("Hello world!"));
三、实现
- 1、单例EventBus
/** 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;
}
- 2、注册
/**注册时,通过反射找到订阅者中订阅事件的方法 */
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
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");
}
}
}
/**将事件类型-订阅者及其方法分别作为:key-value放到Map中*/
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
- 3、发布事件
/**根据事件类型,从上面"注册"时的提到Map中找到订阅者及其方法*/
private boolean postSingleEventForEventType() {
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
......
}
/**根据订阅者方法的注解参数threadMode {@Subscribe(threadMode = ThreadMode.MAIN)},在不同线程调用订阅者方法*/
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
}
}
threadMode,线程模式,主要有以下类型:
/**在哪个线程发布的事件,就在哪个线程调用订阅者订阅事件方法,默认模式*/
ThreadMode.POSTING
/**若在主线程发布的事件,则直接在主线程调用订阅者方法;若是在子线程发布的事件,事件会被先加入队列,
利用Handler切到主线程后,在主线程依次调用订阅者方法*/
ThreadMode.MAIN
/**在任意线程发布的事件,事件都先被加入队列,利用Handler切到主线程后,在主线程依次调用订阅者方法*/
ThreadMode.MAIN_ORDERED
/**若在子线程发布的事件,则直接在子线程调用订阅者方法;若是在主线程发布的事件,事件会被加入队列,然后在单
个后台线程中依次调用订阅者方法*/
ThreadMode.BACKGROUND
/**在任意线程发布的事件,事件都先被加入队列,然后分别在新线程中调用订阅者方法*/
ThreadMode.ASYNC
四、优缺点
- 1、优点
项目开发时,App的各组件间、组件与后台线程间需要进行通信(例:在子线程中进行请求数据,当数据请求完毕通过
Handler,Broadcast等方式通知UI).当项目变复杂时会出现代码量大耦合度高的问题,EventBus可以代替这些传统的通信
方式,简化组件之间的通信、将事件发送者和接收者分离(github官方观点) - 2、缺点
反射的可能会影响一些效率、事件可能会纠缠(例:订阅者方法中直接、间接抛出其他事件),业务量大时会出现
“Events were posted everywhere for everything”,难调试 [1] [2]
五、参考
https://github.com/greenrobot/EventBus
http://greenrobot.org/eventbus/documentation/
https://baike.baidu.com/item/EventBus/20461274
https://endlesswhileloop.com/blog/2015/06/11/stop-using-event-buses/
https://medium.com/@gmirchev90/its-21st-century-stop-using-eventbus-3ff5d9c6a00f