之前,对于activity和fragment之间的通讯可使用接口的方式,定义起来比较麻烦费事,偶然间发现可使用EventBus,发现很好用,查看了一下官方说明:EventBus是针一款对Android的发布/订阅事件总线。它可让咱们很轻松的实如今Android各个组件之间传递消息,而且代码的可读性更好,耦合度更低。可是在用的过程当中总会出现一些问题,下面就将出现的问题详细记录一下,顺便具体学习EventBus(GreenRobot)这个第三方开源库,了解它内部的实现原理,以致于出了问题能够快速定位修复。java
官网: greenrobot.org/eventbus/do…git
github: github.com/greenrobot/…github
EventBus3.0。
复制代码
对于EventBus的原理呢,能够参照一下官网的这张图: 缓存
具体的使用方法能够看官网,很简单,简单罗列一下:bash
compile 'org.greenrobot:eventbus:3.0.0'
复制代码
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
复制代码
// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
复制代码
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
复制代码
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
复制代码
以上即是官网给出的简单使用步骤,也不是很难,因此就不须要翻译了。接下来咱们针对使用过程当中出现的问题来进行一步一步的深刻探究。并发
咱们先来使用一个简单的例子来总结。这个例子主要有三个activity,MainActivity、SecondActivity、ThirdActivity以及一个MessageEvent对象。咱们在MainActivity、SecondActivity中分别注册了MessageEvent事件,在ThirdActivity中post MessageEvent事件,这样咱们在MainActivity、SecondActivity中应该都能接受到该事件。下面是具体的代码。app
第一个MainActivityasync
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
Button btn = (Button) findViewById(R.id.button2);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, SecondActivity.class));
}
});
}
//接收事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void fresh(MessageEvent messageEvent) {
M2Log.d("MessageEvent -----------------> MainActivity");
}
@Override
protected void onDestroy() {
super.onDestroy();
M2Log.d("MainActivity -----------------> onDestroy");
EventBus.getDefault().unregister(this);
}
}
复制代码
第二个SecondActivityide
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
EventBus.getDefault().register(this);
Button btn = (Button) findViewById(R.id.btn2);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(SecondActivity.this, ThirdActivity.class));
}
});
}
//接收事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void fresh(MessageEvent messageEvent) {
M2Log.d("MessageEvent -----------------> SecondActivity");
}
@Override
protected void onDestroy() {
super.onDestroy();
M2Log.d("SecondActivity -----------------> onDestroy");
EventBus.getDefault().unregister(this);
}
}
复制代码
第三个ThirdActivityoop
public class ThirdActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
Button btn = (Button) findViewById(R.id.btn3);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//发送消息
EventBus.getDefault().post(new MessageEvent(""));
finish();
}
});
}
}
复制代码
打印输出结果
很显然,MainActivity和SecondActivity都接收到了MessageEvent事件。
细心的会发现,咱们
EventBus.getDefault().register(this);
EventBus.getDefault().unregister(this);
复制代码
注册生命周期是放在onCreate()和onDestroy()中的,若是咱们按照官网上来,放在onStart()和onStop()中,你就会发现,咱们接收不到MessageEvent事件,能够验证一下
@Override
protected void onStart() {
super.onStart();
M2Log.d("SecondActivity -----------------> onStart");
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
M2Log.d("SecondActivity -----------------> onStop");
EventBus.getDefault().unregister(this);
}
复制代码
结果是什么都不会打印,因此咱们通常会将注册生命周期放到onCreate()和onDestroy()中去。
咱们在开发过程当中,你会发现有的时候会出现问题:
一、没有注册该事件
出现这种状况,大多数是没有注册该事件,什么意思呢?就是下面的相似代码没有写。
@Subscribe(threadMode = ThreadMode.MAIN)
public void fresh(MessageEvent messageEvent) {
M2Log.d("MessageEvent -----------------> MainActivity");
}
复制代码
有的人写了相似的注册代码,但仍是会报这个错误,那就涉及到注册的生命周期了。
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
复制代码
二、屡次注册
这是咱们在生命周期中注册该事件时屡次注册形成的。解决方法很简单,能够判断一下
//没有注册时再进行注册操做
if (!EventBus.getDefault().isRegistered(this)){
EventBus.getDefault().register(this);
}
复制代码
粘性事件Sticky Events 粘性事件相似于粘性广播,就是一次注册永久使用。
如何使用呢?相似于前面的,只不过加了一个sticky = true,发送时采用postSticky而已
//发布事件
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
复制代码
在接收的时候添加一个sticky = true便可。
//注册接收
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void fresh(MessageEvent messageEvent) {
M2Log.d("MessageEvent -----------------> SecondActivity");
}
@Override
protected void onStart() {
super.onStart();
M2Log.d("SecondActivity -----------------> onStart");
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
M2Log.d("SecondActivity -----------------> onStop");
EventBus.getDefault().unregister(this);
}
复制代码
咱们前面出现过一个问题,那就是咱们在onStart和onStop中注册,接收不到EventMessage,经过粘性事件,就能够解决这个问题。不过当你使用粘性事件时你会发现,每次进入注册该事件的activity中都会主动接收到该事件。
下面是我发送了一个粘性事件,咱们在MainActivity 和 SecondActivity中会接收到该事件,咱们退出APP后,再次进入,则又会接收到该事件。
清除粘性事件
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// "Consume" the sticky event
EventBus.getDefault().removeStickyEvent(stickyEvent);
// Now do something with it
}
/**
* threadMode
* 表示方法在什么线程执行 (Android更新UI只能在主线程, 因此若是须要操做UI, 须要设置ThreadMode.MainThread)
*
* sticky
* 表示是不是一个粘性事件 (若是你使用postSticky发送一个事件,那么须要设置为true才能接受到事件)
*
* priority
* 优先级 (若是有多个对象同时订阅了相同的事件, 那么优先级越高,会优先被调用.)
* */
@Subscribe(threadMode = ThreadMode.MainThread, sticky = true, priority = 100)
public void onEvent(MsgEvent event){
}
复制代码
上面即是EventBus3.0的常规用法,咱们在知道了常规用法后还不行,必须深刻了解一下它的内部实现原理,不然到时候出了问题后不知道该如何解决,要知其然而之因此然。下面咱们便来分析一下它的源码。
源码解析部分主要从register、post、以及unregisger这三部分进行分析。
咱们首先从注册入手,先分析
EventBus.getDefault() 进入源码:
static volatile EventBus defaultInstance;
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
复制代码
EventBus是单例模式存在的,使用了双重判断的方式,防止并发的问题,还能极大的提升效率。接着进入register(this)进行分析
//**EventBus.class ---> register**
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
//反射调用,获取订阅者的类对象
Class<?> subscriberClass = subscriber.getClass();
//获取订阅者全部的订阅方法以@Subscribe为注解的一些public方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//依次注册这些订阅方法
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//对订阅方法进行注册
subscribe(subscriber, subscriberMethod);
}
}
}
复制代码
其中有获取订阅方法的代码
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
复制代码
咱们进入,分析一下,如何获取订阅方法。首先来看一下订阅方法的类
//**SubscriberMethod.class**
/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
final Method method; //方法
final ThreadMode threadMode; //执行线程
final Class<?> eventType; //接收的事件类型
final int priority; //优先级
final boolean sticky; //粘性事件
/** Used for efficient comparison */
String methodString;
//...省略部分代码
}
复制代码
SubscriberMethod是一个订阅方法的实体类,里面存储了订阅方法的一些基本信息,订阅方法就是在类中以@Subscribe为注解的一些public方法,注意是public方法不然会报错,为何是public方法咱们下面会分析,给出缘由,而后进入subscriberMethodFinder.findSubscriberMethods(subscriberClass),该代码的做用主要是获取当前类中全部的订阅方法。咱们来看看是如何获取一个订阅者全部的订阅方法的:
//**SubscriberMethodFinder.class**
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//从缓存中获取订阅方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//是否忽略注解器生成的MyEventBusIndex类
if (ignoreGeneratedIndex) {
//利用反射来获取订阅类中的订阅方法信息
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//从注解器生成的MyEventBusIndex类中得到订阅类的订阅方法信息
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;
}
}
复制代码
对于获取咱们注册的订阅方法,首先就是经过缓存来获取,若是没有的话则经过如下两种方式进行获取:
EventBusAnnotationProcessor注解生成器在编译期经过读取@Subscribe()注解并解析,处理其中所包含的信息,而后生成java类来保存全部订阅者关于订阅的信息。 运行时使用反射来得到这些订阅者的信息 对于这两种方式的分析,能够参考http://www.jianshu.com/p/f057c460c77e这里面相关的内容。
对于第一种方法没什么好说的,咱们来分析一下经过反射来获取这些订阅方法的方式,接下来分析经过反射获取当前类中的订阅方法
//**SubscriberMethodFinder.class**
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
//FindState其实就是一个里面保存了订阅者和订阅方法信息的一个实体类,包括订阅类中全部订阅的事件类型和全部的订阅方法等。
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获取订阅方法
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
复制代码
代码不是太多,里面涉及到一个类FindState,咱们来看下,这是什么东西,
static class FindState {
//订阅方法
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//以event为key,以method为value
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//以method的名字生成一个methodKey为key,该method的类(订阅者)为value
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
//...省略部分代码
}
复制代码
这个FindState其实就是一个里面保存了订阅者和订阅方法信息的一个实体类,包括订阅类中全部订阅的事件类型和全部的订阅方法等。咱们接着分析下面的代码。
findUsingReflectionInSingleClass(findState)
复制代码
这行代码即是获取订阅方法列表的重要代码,咱们进入查看一下:
//**SubscriberMethodFinder.class**
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();
//订阅方法必须是must be public, non-static, and non-abstract
//获取订阅方法参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
//注解方法必须只有一个参数
if (parameterTypes.length == 1) {
//获取订阅方法的注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
//该订阅方法包含Subscribe注解
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");
}
}
}
复制代码
能够看到,首先会获得订阅类的class对象并经过反射获取订阅类中的全部方法信息,而后经过筛选获取到订阅方法集合。这里面就解释了为何要以@Subscribe为注解的方法,且必须是public类型,方法参数只有一个的缘由。
//**Subscribe.java**
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
复制代码
注解,分为三种参数,
ThreadMode,方法执行的线程,POSTING(默认值)、MAIN、BACKGROUND、ASYNC
sticky,粘性时间,默认值false
priority,优先级,默认值0
该方法流程是:
拿到当前 class 的全部方法 过滤掉不是 public 和是 abstract、static、bridge、synthetic 的方法 过滤出方法参数只有一个的方法 过滤出被Subscribe注解修饰的方法 将 method 方法和 event 事件添加到 findState 中 将 EventBus 关心的 method 方法、event 事件、threadMode、priority、sticky 封装成SubscriberMethod 对象添加到 findState.subscriberMethods 列表中 经过上面几步,咱们就能够得到了所订阅的方法,而后分别进行注册这些订阅方法。经过下面的代码来执行:
//参数:1订阅者 2订阅方法
subscribe(subscriber, subscriberMethod);
复制代码
接着分析这个注册方法。
//**EventBus.java**
// Must be called in synchronized block
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);
}
//将该事件类型添加到typesBySubscriber中
subscribedEvents.add(eventType);
//若是接收sticky事件,当即分发sticky事件
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.java
//订阅者信息
final class Subscription {
final Object subscriber;//订阅者
final SubscriberMethod subscriberMethod;//订阅方法
}
//subscriptionsByEventType
key订阅方法类型 values 全部订阅了该类型的订阅者集合
Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//typesBySubscriber
key订阅者 values订阅事件集合
Map<Object, List<Class<?>>> typesBySubscriber;
复制代码
了解了这几个对象,上面的代码就很容易看懂了,
分析了注册事件后,咱们来分析一下分发事件post的流程,首先经过
EventBus.getDefault().post(new MessageEvent(""));
复制代码
这行代码进行事件消息的分发,咱们进入到post中详细了解一下这个流程。
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> 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 {
//分发事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
复制代码
代码虽然不长,可是不大好理解,这里面多了一些不常见的对象,咱们来看下,首先对于第一行代码:
PostingThreadState postingState = currentPostingThreadState.get();
复制代码
这里面的PostingThreadState是什么意思呢?
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
//当前线程的事件队列
final List<Object> eventQueue = new ArrayList<Object>();
//是否有事件正在分发
boolean isPosting;
//post的线程是不是主线程
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
复制代码
PostingThreadState中包含了当前线程的事件队列,就是当前线程全部分发的事件都保存在eventQueue事件队列中以及订阅者订阅事件等信息,有了这些信息咱们就能够从事件队列中取出事件分发给对应的订阅者。
咱们接着分析,对于这个当前线程的事件队列,咱们是经过currentPostingThreadState.get();来获得的,对于这个currentPostingThreadState又是什么呢?
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
复制代码
ThreadLocal 是一个线程内部的数据存储类,经过它能够在指定的线程中存储数据,而这段数据是不会与其余线程共享的。能够看出currentPostingThreadState的实现是一个包含了PostingThreadState的ThreadLocal对象,这样能够保证取到的都是本身线程对应的数据。
接着就经过postSingleEvent(eventQueue.remove(0), postingState);来对事件进行分发。
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) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
复制代码
事件的分发最后还要经过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;
}
复制代码
//将事件分发给对应的订阅者
//将事件分发给对应的订阅者
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 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);
}
}
复制代码
代码比较简单,它们最终是经过发射调用来将事件分发给对应的订阅者的:
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);
}
}
复制代码
以上即是事件的分发过程,咱们总结归纳一下:
最后咱们来分析一下取消订阅的方法:
/** Unregisters the given subscriber from all event classes. */
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 {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//获取事件类型的全部订阅者
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//遍历订阅者集合,将解除的订阅者移除
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
复制代码
代码很简单,最后总结一下取消订阅的流程。
以上即是EventBus全部的工做流程,咱们来简单说明一下:
register
post
unregister
专一于 Android 开发多年,喜欢写 blog 记录总结学习经验,blog 同步更新于本人的公众号,欢迎你们关注,一块儿交流学习~