EventBus是Android上的订阅事件总线,它简化了各组件间组件和后台之间的通信,使用订阅者和发布者模式进行解耦,使用方便。
使用EventBus的好处:
1)简化了组件之间的通信
2)将事件发送者和接收者分离
3)在UI之间(Activity,Fragment),后台线程中表现良好
4)避免复杂并且容易出错的依赖关系和生命周期问题。
5)很快,专门针对高性能进行了优化
6)很小jar包<50k
7)具有交付线程,用户优先级等高级功能
EventBus 特色
1)方便的基于注解的API,只需将@Subscribe注解放到订阅者方法上即可。EventBus不需要在应用程序的运行时进行注释反射。
2)当和UI交互的时候,无论实践如何发布,EventBus都可以在主线程中传递事件
3)如果订阅者长时间运行任务,EventBus也可以使用后台线程来避免线程阻塞
4)如果事件A是事件B的父类,那么事件B的已发布事件也将发给订阅了A的订阅者
开始使用
第一步:gradle中添加依赖
implementation 'org.greenrobot:eventbus:3.1.1'
第二步:定义事件
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
第三步:准备订阅者
方法名字自己可以随便定义,只要方法上面加@Subscribe注解就行
// 当MessageEvent消息发布的时候,该方法可以收到消息,在UI线程中显示toast
@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);
}
第四步:订阅者需要在事件总线中注册和注销,只有注册了才能收到事件
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
不一定非得在onStart()和onStop()中,根据自己的需要,可以在onCreate()中和onDestory()中。
第五步:发布事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
发从黏性事件:
跟系统的黏性广播类似,就是在发送事件之后再订阅该事件,也能收到该事件
EventBus.getDefault().postSticky(new MyEvent());
线程模型
在EventBus中可以使用下面几种线程模型来定义将调用事件处理方法的线程
POSTING(默认):
发布事件和订阅事件在同一个线程中,事件传递是同步完成的,一旦发布完成,所有的订阅者都将被调用,这种线程模型开销最小,因为它完全避免了线程切换,因此完成简单任务推荐使用这种模式。避免在此模式下执行耗时操作,因为它会阻塞事件的传递,甚至引起ANR。
MAIN :
事件处理将在Android的主线程中进行,使用此模式必须快速返回避免阻塞主线程。
MAIN_ORDERED:
订阅者将在Android主线程中调用,该事件总是排队等待以后交付给订阅者,因此对post的调用将立即返回,为事件处理提供了更严格一直的顺序。
BACKGROUND:
如果事件是在主线程中发布,则另起一个线程来处理事件,如果发布线程不是主线程,则在发布线程中调用。这个事件处理函数中禁止更新UI
ASYNC:
无论事件在哪个线程中发布,该函数都会重新建立一个线程来处理事件。
EventBus源码解析
当我们使用EventBus的时使用EventBus.getDefault()
来获取EventBus的实例那就从它来开始
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
可以看到这一个双重校验的单例模式创建了EventBus的实例。然后看看其构造方法:
public EventBus() {
this(DEFAULT_BUILDER);
}
//这里的DEFAULT_BUILDER是一个Builder的成员变量,用来构造EventBus
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
this调用了其一个参数的构造方法
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;
}
可以看到构造方法中初始化了很多Map:subscriptionsByEventType,typesBySubscriber,stickyEvents 来保存订阅的方法,订阅者监听的事件类型,黏性事件。
还有几个Poster:mainThreadPoster,backgroundPoster,asyncPoster
这几个Poster是啥呢?他们都实现了Poster接口,Poster接口里面有个入队的方法。
interface Poster {
void enqueue(Subscription subscription, Object event);
}
mainThreadPoster:
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
...
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
...
public class HandlerPoster extends Handler implements Poster {}
可以看到mainThreadPoster是一个Handler。
backgroundPoster:
class BackgroundPoster implements Runnable, Poster {}
可以看到backgroundPoster是一个Runnable
asyncPoster:
AsyncPoster implements Runnable, Poster {}
asyncPoster也是一个Runnable
我们知道Handler,Runnable都是负责线程调度的嘛,其实对应的就是上面说的那几种模式,OK先知道这几个然后往下看,EventBus其实就是一个订阅者消费者模式,那就从注册订阅者开始
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//通过findSubscriberMethods方法找到subscriber类中的订阅的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
从上面的代码可以看到通过SubscriberMethodFinder的findSubscriberMethods方法找到subscriber类中的订阅的方法,SubscriberMethodFinder在构造方法中初始化好的 ,然后遍历找到的这些方法,通过subscribe方法完成订阅,先看看怎么找的
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//先从缓存中找,如果有就直接返回
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//是否忽略注解生成器
if (ignoreGeneratedIndex) {
//通过反射获取subscriberMethods
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
先从缓存中取,如果有直接返回,如果没有判断是否忽略注解生成器ignoreGeneratedIndex如果是采用反射回去方法,如果不是用另一个方法。ignoreGeneratedIndex默认是false,所以我们通常使用的是findUsingInfo这个方法来获取订阅的方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//准备一个FindState
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获取订阅者信息,没有配置MyEventBusIndex返回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);
}
先看一下FindState
static class FindState {
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
......
可以看大FindState就是一个包装 类,里面有各种list和各种Map来保存订阅方法,订阅类
回到findUsingInfo方法继续往下,通过getSubscriberInfo方法来获取订阅者信息,因为我们前面使用的是忽略注解生成器,所以会返回null,然后进入findUsingReflectionInSingleClass方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
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");
}
}
}
此方法中,通过反射找到该类中的所有方法,然后遍历方法,找到带Subscribe注解的方法也就是订阅的方法,和这个方法的相关信息,封装成SubscriberMethod对象最后保存到findState中的subscriberMethods这个list中。
最后调用getMethodsAndRelease方法并返回
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
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存到缓存池里,然后返回订阅方法的信息。
OK到这里就返回了这个类中的所有订阅方法的信息的集合,也就是加了@Subscribe注解的方法的信息,然后可以在回到register注册方法中继续往下了,下面就是遍历这些方法进行订阅了,看看怎么订阅的呢
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> 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);
}
}
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;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
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);
}
}
}
这里把传进来的类和类中的订阅方法集合重新封装到一个对象Subscription中,CopyOnWriteArrayList是一个线程安全的list
保存到subscriptionsByEventType这个map中,以参数类型为key,方法信息为value
然后进行优先级的判断优先级越高,会插到在当前List靠前面的位置;
通过订阅者获取该订阅者所订阅事件的集合,如果获取不到就创建一个放入Map typesBySubscriber中。
将当前的订阅事件添加到subscribedEvents中
最后判断是不是黏性事件,黏性事件最后都会调用checkPostStickyEventToSubscription方法。
总结:这里面做了两件事,第一件,把订阅方法和订阅者放到subscriptionsByEventType和typesBySubscriber这两个Map中保存。subscriptionsByEventType就是当发送事件的时候根据EventType找打订阅事件然后去处理。typesBySubscriber是在调用unregister(this)的时候,根据订阅者找到EventType,在根据EventType找到订阅事件进行解绑。第二件事就是如果是黏性事件,就立马执行。
到这里注册就告一段落啦,下面看看事件的发送
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
currentPostingThreadState是一个ThreadLocal类里面存储的是PostingThreadState里面保存了事件队列和线程状态的信息。ThreadLocal我们知道它是一个线程安全的对象封装,相当于一个线程中的局部变量。
获取事件队列,并把事件放进队列中
最后从队列中取出事件调用postSingleEvent来处理事件
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));
}
}
}
首先取出事件类的类型
eventInheritance表示是否向上查找事件的父类,默认为true
通过lookupAllEventTypes找到所有Event和其父类事件并存在List中
通过postSingleEventForEventType方法对事件逐一处理。从名字就可以看出根据事件类型发送一个事件。
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
从subscriptionsByEventType中取出对应的subscriptions(订阅方法信息)。
把这个Event和取出的subscriptions封装到PostingThreadState中
调用postToSubscription来处理事件
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;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
这里看到了熟悉的,刚开始使用的时候接触到的集中线程模式。那这里就是根据这几种线程模式来分别处理事件。
**POSTING:**调用invokeSubscriber方法来处理事件
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
其实就是执行一开始通过反射得到的订阅方法,把事件传过去。
**MAIN:**如果是主线程,就直接执行反射方法,反之则使用mainThreadPoster的入队方法入队到把事件和订阅方法封装到PendingPost中然后放到PendingPostQueue这个链表中。PendingPost顾名思义就是将要执行的post,一开始的构造方法中我们知道mainThreadPoster其实就是个Handler,所以具体执行方法就在其handleMessage中执行
@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;
}
}
其实就是把刚才放到队列中的PendingPost取出来,去执行反射方法
MAIN_ORDERED: 在主线程中有序的执行
可以看到这里跟MAIN的区别是这里不是先判断是不是主线程,而是先判断mainThreadPoster是不是null,如果不是null就直接入队。我们知道mainThreadPoster在构造方法中就初始化好了,所以不为null。所以不管是在哪个线程,都一律去handler中去排队执行。
BACKGROUND:
如果不是主线程,就直接执行invokeSubscriber,执行反射中的方法;如果是主线程就使用backgroundPoster的入队方法入队到把事件和订阅方法封装到PendingPost中然后放到PendingPostQueue这个链表中。backgroundPoster我们在最开始的构造方法中知道他是一个Runnable,所以其具体执行方法就在其run方法中
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
把刚才放到队列中的PendingPost取出来,去执行反射方法
ASYNC: 直接调用asyncPoster的入队方法,asyncPoster也是一个Runnable,所以其具体执行方法就在其run方法中
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
把刚才放到队列中的PendingPost取出来,去执行反射方法
BACKGROUND和ASYNC都是一个Runnable,但是我们可以看到他们的run方法和入队的方法中的实现并不一样,BACKGROUND中有个executorRunning,判断当前是不是又正在执行的。所以BACKGROUND是一个一个执行的,ASYNC是同事异步执行的。
最后是取消订阅
public synchronized void unregister(Object subscriber) {
List<Class<?>> 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());
}
}
就是把存到subscriptionsByEventType和typesBySubscriber中的订阅方法和这个类对象移除。
总结:
当我们注册的时候,把要注册的类保存到typesBySubscriber这个Map中,把这个类中的订阅方法和订阅方法的各种参数信息保存到subscriptionsByEventType这个Map中,key是事件的类型。当发送事件的时候,根据事件的类型,从subscriptionsByEventType中找到对应的订阅方法,然后执行这些方法。取消注册的时候,把存到subscriptionsByEventType和typesBySubscriber中的订阅方法和这个类对象移除。