-
使用过程
定义事件:
public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } }定义事件回调(方法名没有限制):
在MainActivity中定义事件回调
@Subscribe(threadMode = ThreadMode.MAIN) public void process(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_LONG).show(); }EventBus有5种
ThreadMode:public enum ThreadMode { //在发送事件的线程执行回调 POSTING, //在主线程执行,如果发送线程是主线程,则同步执行回调;如果不是主线程,则把回调放入主线程消息队列 MAIN, //直接将回调放入主线程消息队列 MAIN_ORDERED, //回调在子线程中执行。如果发送线程非子线程,则直接同步执行回调;如果是主线程,则EventBus会新建一个子线程,并把所有的这种类型的事件放到这个线程中执行 BACKGROUND, //子线程异步执行,一般不是主线程,也不是事件发送线程 ASYNC }注册和解绑EventBus监听
如在MainActivity中进行:
@Override protected void onCreate() { super.onCreate(); EventBus.getDefault().register(this); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); }发送事件:
EventBus.getDefault().post(new MessageEvent("hello")); -
其他情况的处理
-
发送的事件没有监听器
//发送了字符串,但是没有对应的字符串类型的事件回调 EventBus.getDefault().post("hello");if (!subscriptionFound) { if (logNoSubscriberMessages) { logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } }如果配置了
EventBusBuilder的logNoSubscriberMessages,会打印日志;如果配置了
sendNoSubscriberEvent,则会触发一个NoSubscriberEvent事件 -
黏性事件
概念:EventBus会为每个事件类型保存最近一次的事件。当监听者进行注册时,会将缓存的事件发送给它。
使用场景:跨生命周期或者异步调用等场景可以使用
举例:从MAinActivity跳转到SecondActivity时,发送一个黏性事件;在SecondActivity注册EventBus时,会触发该黏性事件
EventBus.getDefault().postSticky(new MessageEvent("ss")); Intent it = new Intent(MainActivity.this, SecondActivity.class); MainActivity.this.startActivity(it);SecondActivity中定义黏性事件的回调
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void process(MessageEvent e){ Toast.makeText(this, "sticky", Toast.LENGTH_LONG).show(); }在onCreate中向EventBus注册回调,就会触发回调
EventBus.getDefault().register(this);原理(黏性事件分发):
public void postSticky(Object event) { synchronized (stickyEvents) { //1 每种黏性事件最近的一个实例会被保存 stickyEvents.put(event.getClass(), event); } //2 事件也会继续分发 // Should be posted after it is putted, in case the subscriber wants to remove immediately post(event); }注册时的处理逻辑:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { ...... //注册时,如果回调方法是黏性的,则会将保存的黏性事件分发出去,触发该回调方法 if (subscriberMethod.sticky) { if (eventInheritance) { Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); for (Map.Entry<Class<?>, 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); } } } -
事件有继承关系
-
定义了一个回调,事件类型是Object
@Subscribe(threadMode = ThreadMode.MAIN) public void process(Object event) { Toast.makeText(this, event.toString(), Toast.LENGTH_LONG).show(); }当发送任意其他类型的事件时,也会触发这个回调,原因在EventBus中有一个
eventInheritance变量进行控制,默认为true,会响应该事件及其父类的回调方法private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; if (eventInheritance) { //需要响应该事件的全部事件类型 List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } if (!subscriptionFound) { if (logNoSubscriberMessages) { logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }lookupAllEventTypes方法会遍历所有的事件类型,包括其父类private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); addInterfaces(eventTypes, clazz.getInterfaces()); //事件类型的父类,包括Object clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; } }如果不需要响应该事件的父类的回调,可以将
eventInheritance置为false@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //不使用默认的EventBus实例 EventBus.builder().eventInheritance(false).installDefaultEventBus(); EventBus.getDefault().register(this); }-
定义了一个回调,事件类型是SubMessageEvent,继承自MessageEvent
@Subscribe(threadMode = ThreadMode.MAIN) public void process(MessageEvent event) { Toast.makeText(this, "Object", Toast.LENGTH_LONG).show(); } @Subscribe(threadMode = ThreadMode.MAIN) public void processSub(SubMessageEvent event) { Toast.makeText(this, "SubMessageEvent", Toast.LENGTH_LONG).show(); }发送SubMessageEvent事件,如果
eventInheritance为true,会触发上述两个回调,否则只会触发SubMessageEvent的回调发送MessageEvent事件,只会触发MessageEvent的回调
-
-
订阅者有继承关系
SecondActivity继承自MainActivity,触发MessageEvent事件,则SecondActivity能够响应事件回调
//EventBus.findSubscriberMethods()会调用findUsingReflection()或findUsingInfo()寻找注册类上定义的回调,会遍历循环到父类中使用Subscribe注解的方法 private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); //在父类中寻找监听器 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); } private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { 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 { findUsingReflectionInSingleClass(findState); } //在父类中寻找监听器 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); } -
错误事件
EventBus提供了AsyncExecutor和ThrowableFailureEvent来捕获异常,并发送异常事件
过程:
- 创建一个AsyncExecutor实例,配置了线程池,EventBus实例,及错误事件类型
- 执行一个RunnableEx
- 捕获运行时异常,并用EventBus发送一个错误事件
//AsyncExecutor中的execute方法,参数类型是RunnableEx,需实现run方法,该方法会抛出异常 public void execute(final RunnableEx runnable) { threadPool.execute(new Runnable() { @Override public void run() { try { runnable.run(); } catch (Exception e) { Object event; try { event = failureEventConstructor.newInstance(e); } catch (Exception e1) { eventBus.getLogger().log(Level.SEVERE, "Original exception:", e); throw new RuntimeException("Could not create failure event", e1); } if (event instanceof HasExecutionScope) { ((HasExecutionScope) event).setExecutionScope(scope); } eventBus.post(event); } } }); }配合ErrorDialogManager可以在接收到错误事件时,弹一个DialogFragment
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this); //配置错误弹窗的标题和内容 ErrorDialogConfig cfg = new ErrorDialogConfig(getResources(),R.string.app_name, R.string.app_name); cfg.setEventBus(EventBus.getDefault()); //创建fragment ErrorDialogManager.factory = new ErrorDialogFragmentFactory.Support(cfg); //将fragment绑定到activity ErrDialogMgr.attachTo(this); findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AsyncExecutor.create().execute(new AsyncExecutor.RunnableEx() { @Override public void run() throws Exception { Object x = null; //抛出一个空指针异常 x.toString(); } }); } }); }点击按钮会触发空指针异常,EventBus触发一个
ThrowableFailureEvent事件,ErrorDialogManager中注册了对应的回调,响应后会显示一个dialog注:由于
ErrorDialogManager的SupportManagerFragment和HoneycombManagerFragment在onResume()时会调用EventBus.register()方法,但是onEventMainThread(ThrowableFailureEvent event)没有增加@Subscribe(threadMode = ThreadMode.MAIN)注解,会抛异常崩溃。 解决:把这几个类复制出来,并在onEventMainThread方法上增加注解,能够弹窗 这个问题已给EventBus提issue-
调用了注册
register(),但是没有定义事件处理回调,即没有使用@Subscribe注解会抛出一个异常
throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); -
定义了多个同事件的回调
@Subscribe(threadMode = ThreadMode.MAIN) public void process1(MessageEvent event) { Toast.makeText(this, "process111", Toast.LENGTH_LONG).show(); } @Subscribe(threadMode = ThreadMode.MAIN) public void process2(MessageEvent event) { Toast.makeText(this, "process222", Toast.LENGTH_LONG).show(); }如果定义了
MessageEvent的两个回调方法,当触发MessageEvent事件时,只有第一个方法会执行。源码解释:
EventBus.findUsingInfo() => FindState.checkAdd() => FindState.checkAddWithMethodSignature() private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) { methodKeyBuilder.setLength(0); methodKeyBuilder.append(method.getName()); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); Class<?> methodClass = method.getDeclaringClass(); Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; } else { // Revert the put, old class is further down the class hierarchy // 如果同一个事件已经定义过回调,则使用之前的,不会用新方法替换 subscriberClassByMethodKey.put(methodKey, methodClassOld); return false; } }
-
使用注解
运行时通过反射查找注解,会有一些性能损失。EventBus提供了注解处理器,在编译时生成辅助类,提升性能。
使用过程
配置项目的build.gradle:
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
配置module的build.gradle:
android {
defaultConfig {
javaCompileOptions {
// 注解处理器参数配置
annotationProcessorOptions {
// 配置参数名和值
arguments = [ eventBusIndex :
'com.example.myapplication.EventBusIndex' ]
}
}
}
}
dependencies {
// 配置注解处理器
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}
make project之后,在build/source/apt/debug/下可以看到生成的辅助类,可以看到方法有Subscribe注解的类都会把类名与定义的回调方法都保存在SUBSCRIBER_INDEX中
package com.example.myapplication;
import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
import org.greenrobot.eventbus.meta.SubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;
import org.greenrobot.eventbus.ThreadMode;
import java.util.HashMap;
import java.util.Map;
/** This class is generated by EventBus, do not edit. */
public class EventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(com.example.hero.myapplication.MainActivity.class, true,
new SubscriberMethodInfo[] {
new SubscriberMethodInfo("process1", com.example.hero.myapplication.event.MessageEvent.class,
ThreadMode.MAIN),
}));
}
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;
}
}
}
添加生成的辅助类,需要在实例化EventBus之前添加
EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
EventBus.getDefault().register(this);
注解处理器
注解处理器主要有三个步骤
- 收集订阅者,遍历每个Subscribe注解,把类和方法存储到一个ListMap中
- 过滤订阅者,类和方法需要满足一定的条件
- 生成java文件
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
...
collectSubscribers(annotations, env, messager);
checkForSubscribersToSkip(messager, indexPackage);
createInfoIndexFile(index);
...
return true;
}
收集订阅者
private void collectSubscribers(Set<? extends TypeElement> annotations,
RoundEnvironment env, Messager messager) {
for (TypeElement annotation : annotations) {
//遍历注解,获取每个加了注解的方法
Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);
for (Element element : elements) {
if (element instanceof ExecutableElement) {
ExecutableElement method = (ExecutableElement) element;
//方法不是static,必须是public,且只有一个参数
if (checkHasNoErrors(method, messager)) {
//方法所在的类
TypeElement classElement = (TypeElement)
method.getEnclosingElement();
//methodsByClass是一个ListMap
methodsByClass.putElement(classElement, method);
}
} else {
messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid
for methods", element);
}
}
}
}
过滤订阅者
private void checkForSubscribersToSkip(Messager messager, String myPackage) {
for (TypeElement skipCandidate : methodsByClass.keySet()) {
TypeElement subscriberClass = skipCandidate;
while (subscriberClass != null) {
//类的修饰符是public,则可见
//类的修饰符是private或protected,则不可见
//类的修饰符是默认的,则需要生成的辅助类的包名与注解所在类的包名一样
if (!isVisible(myPackage, subscriberClass)) {
boolean added = classesToSkip.add(skipCandidate);
if (added) {
String msg;
if (subscriberClass.equals(skipCandidate)) {
msg = "Falling back to reflection because class is not
public";
} else {
msg = "Falling back to reflection because " + skipCandidate +
" has a non-public super class";
}
messager.printMessage(Diagnostic.Kind.NOTE, msg, subscriberClass);
}
break;
}
List<ExecutableElement> methods = methodsByClass.get(subscriberClass);
if (methods != null) {
for (ExecutableElement method : methods) {
String skipReason = null;
VariableElement param = method.getParameters().get(0);
TypeMirror typeMirror = getParamTypeMirror(param, messager);
//参数类型校验,DeclaredType表示类或者接口,TypeElement表示类或接口
if (!(typeMirror instanceof DeclaredType) ||
!(((DeclaredType) typeMirror).asElement() instanceof
TypeElement)) {
skipReason = "event type cannot be processed";
}
if (skipReason == null) {
TypeElement eventTypeElement = (TypeElement) ((DeclaredType) typeMirror).asElement();
//类的修饰符是public,则可见
//类的修饰符是private或protected,则不可见
//类的修饰符是默认的,则需要生成的辅助类的包名与注解所在类的包名一样
if (!isVisible(myPackage, eventTypeElement)) {
skipReason = "event type is not public";
}
}
if (skipReason != null) {
boolean added = classesToSkip.add(skipCandidate);
if (added) {
String msg = "Falling back to reflection because " + skipReason;
if (!subscriberClass.equals(skipCandidate)) {
msg += " (found in super class for " + skipCandidate + ")";
}
messager.printMessage(Diagnostic.Kind.NOTE, msg, param);
}
break;
}
}
}
subscriberClass = getSuperclass(subscriberClass);
}
}
}
生成java类
//index:在build.gradle中配置的注解处理器的参数——生成类的文件名,包含包名
private void createInfoIndexFile(String index) {
BufferedWriter writer = null;
try {
JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
int period = index.lastIndexOf('.');
//解析包名和类名
String myPackage = period > 0 ? index.substring(0, period) : null;
String clazz = index.substring(period + 1);
writer = new BufferedWriter(sourceFile.openWriter());
if (myPackage != null) {
writer.write("package " + myPackage + ";\n\n");
}
//写入各种依赖
writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
writer.write("import java.util.HashMap;\n");
writer.write("import java.util.Map;\n\n");
writer.write("/** This class is generated by EventBus, do not edit. */\n");
writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
//定义静态常量
writer.write(" private static final Map<Class<?>, SubscriberInfo>
SUBSCRIBER_INDEX;\n\n");
writer.write(" static {\n");
writer.write(" SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>
();\n\n");
//调用putIndex方法,把收集的所有类和类中的全部注解方法保存到SUBSCRIBER_INDEX中
writeIndexLines(writer, myPackage);
writer.write(" }\n\n");
//定义添加回调信息的方法
writer.write(" private static void putIndex(SubscriberInfo info) {\n");
writer.write(" SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
writer.write(" }\n\n");
//实现接口,获取类的订阅信息,包含了所有有注解的方法信息
writer.write(" @Override\n");
writer.write(" public SubscriberInfo getSubscriberInfo(Class<?>
subscriberClass) {\n");
writer.write(" SubscriberInfo info =
SUBSCRIBER_INDEX.get(subscriberClass);\n");
writer.write(" if (info != null) {\n");
writer.write(" return info;\n");
writer.write(" } else {\n");
writer.write(" return null;\n");
writer.write(" }\n");
writer.write(" }\n");
writer.write("}\n");
} catch (IOException e) {
throw new RuntimeException("Could not write source for " + index, e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
//Silent
}
}
}
}
EventBus对生成类的处理过程
- 使用生成的辅助类获取对应类的订阅信息
- 将订阅信息中的SubscriberMethodInfo转换为SubscriberMethod
- 将每个方法和事件类型添加到对应的Map中
- 如果没有注解生成类,则使用反射来获取这个类中每个注解方法的信息
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
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 {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
获取类的订阅者信息
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null &&
findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo =
findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
//从辅助类中获取订阅信息
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
简单的性能对比
在一个类中定义多个回调,增加Subscribe注解,分别使用反射和编译时注解,比较register()的耗时:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
long start = System.currentTimeMillis();
EventBus.getDefault().register(this);
Log.i("EventBus","register spend="+(System.currentTimeMillis()- start));
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(MessageEvent event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(A event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(B event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(C event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(D event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(E event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(F event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(G event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void process(H event) {
Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
多次运行结果:
- 使用编译时注解基本只有方法调用的耗时,非常少,日志显示为0~1ms
- 运行时反射,耗时一般在3~4ms