Descripción general de EventBus
1. Definición
EventBus se utiliza principalmente para la comunicación entre componentes de Android y entre componentes y subprocesos en segundo plano. Es una biblioteca liviana de código abierto para publicación/suscripción de eventos Enciclopedia
de GitHub
2. uso
- 1. Definir eventos
/**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. Los suscriptores se registran y se suscriben a eventos.
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. Eventos de lanzamiento
/**
* 代码的任意位置发布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!"));
3. Realización
- 1. Autobús de eventos Singleton
/** 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. Regístrate
/**注册时,通过反射找到订阅者中订阅事件的方法 */
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. Eventos de lanzamiento
/**根据事件类型,从上面"注册"时的提到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
4. Ventajas y desventajas
- 1. Ventajas
Durante el desarrollo del proyecto, la comunicación debe realizarse entre los componentes de la aplicación y entre los componentes y los subprocesos en segundo plano (por ejemplo: solicitar datos en un subproceso y notificar a la interfaz de usuario a través de Handler, Broadcast, etc. cuando el (se completa la solicitud de datos). Cuando el proyecto se vuelve
complejo. Pueden ocurrir problemas con grandes cantidades de código y alto acoplamiento. EventBus puede reemplazar estos
métodos de comunicación tradicionales, simplificar la comunicación entre componentes y separar remitentes y receptores de eventos (opinión oficial de github) - 2. Desventajas
: la reflexión puede afectar cierta eficiencia y los eventos pueden enredarse (por ejemplo: otros eventos se lanzan directa o indirectamente en el método del suscriptor). Cuando el volumen de negocios es grande, aparecerá "Los eventos se
publicaron en todas partes para todo", dificultando la depuración [1] [2]
5. Referencia
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