一 解析EventBus
EventBus是一款针对Android优化的发布-订阅事件总线。它简化了应用程序内各组件间、组件与后台线程间的通信。其优点是开销小,代码更优雅,以及将发送者和接收者解耦。当一个Android应用功能越来越多的时候,保证应用的各个部分之间高效的通信将变得越来越困难。所以为了解决这个问题,EventBus应运而生!
1.1 EventBus概述
在讲到 EventBus 的基本用法之前,我们需要了解 EventBus 的三要素以及它的 4 种ThreadMode。
EventBus的三要素如下。
• Event:事件。可以是任意类型的对象。
• Subscriber:事件订阅者。在 EventBus 3.0 之前消息处理的方法只能限定于 onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,它们分别代表4种线程模型。而在EventBus 3.0之后,事件处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(默认为POSTING)。
• Publisher:事件发布者。可以在任意线程任意位置发送事件,直接调用 EventBus 的post(Object)方法。可以自己实例化EventBus对象,但一般使用EventBus.getDefault()就可以。根据post函数参数的类型,会自动调用订阅相应类型事件的函数。
EventBus的4种ThreadMode(线程模型)如下。
• POSTING(默认):如果使用事件处理函数指定了线程模型为POSTING,那么该事件是在哪个线程发布出来的,事件处理函数就会在哪个线程中运行,也就是说发布事件和接收事件在同一个线程中。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
• MAIN:事件的处理会在UI线程中执行。事件处理的时间不能太长,长了会导致ANR。
• BACKGROUND:如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行;如果事件本来就是在子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
• ASYNC:无论事件在哪个线程中发布,该事件处理函数都会在新建的子线程中执行;同样,此事件处理函数中禁止进行UI更新操作。
1.2 EventBus基本用法
EventBus基本使用分为以下5个步骤。
(1)自定义一个事件类
public class MessageEvent {
......
}
(2)在需要订阅事件的地方注册事件
EventBus.getDefault().register(this);
(3)发送事件
EventBus.getDefault().post(messageEvent);
(4)处理事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void XXX(MessageEvent messageEvent){
...
}
前面说过,在EventBus3.0以后消息处理的方法可以随便取名,但是需要加一个注解@Subscribe,并且要指定线程模型(默认为POSTING)。
(5)取消事件订阅
EventBus.getDefault().unregister(this);
1.3 EventBus实战
前面讲到了EventBus的基本用法,但是这过于简单,这里举一个例子来应用EventBus。
(1)添加依赖
implementation'org.greenrobot:eventbus:3.0.0'
(2)添加混淆规则
在模块的 proguard-rules.pro 混淆规则文件中添加如下规则:
-keepattributes *Annotation*
-keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# And if you use AsyncExecutor:
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
(3)定义消息事件类
public class MessageEvent {
public String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
(4)注册和取消订阅事件
在MainActivity中注册和取消订阅事件,在 MainActivity 中定义了两个 Button:一个用来注册事件,另一个用来跳转到SecondActivity。代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tv_message;
private Button btn_enter_second_activity, btn_register_event;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_message = findViewById(R.id.tv_message);
btn_enter_second_activity = findViewById(R.id.btn_enter_second_activity);
btn_register_event = findViewById(R.id.btn_register_event);
btn_enter_second_activity.setOnClickListener(this);
btn_register_event.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_enter_second_activity) {
// 跳转到SecondActivity
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
} else if (id == R.id.btn_register_event) {
// 注册事件
EventBus.getDefault().register(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消注册事件
EventBus.getDefault().unregister(this);
}
}
(5)事件订阅者处理事件
在MainActivity中自定义方法来处理事件,在这里ThreadMode设置为MAIN,事件的处理会在UI线程中执行,用TextView来展示收到的事件消息。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
if (event != null && event.getMessage() != null) {
tv_message.setText(event.getMessage());
}
}
(6)事件发布者发布事件
创建了SecondActivity来发布消息,在SecondActivity中,我们定义“发送事件 按钮来发送事件并将SecondActivity finish掉。代码如下所示:
public class SecondActivity extends AppCompatActivity {
private Button btn_send_event;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
btn_send_event = findViewById(R.id.btn_send_event);
btn_send_event.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MessageEvent event = new MessageEvent();
event.setMessage("欢迎学习EventBus");
EventBus.getDefault().post(event);
finish();
}
});
}
}
好了,运行程序,如图1-3-1所示。接下来我们点击MainActivity 中的“注册事件 按钮来注册事件,然后点击“跳转到SecondActivity按钮,这时跳转到SecondActivity,如图1-3-2所示。接下来点击“发送事件 按钮,这个时候 SecondActivity 被 finish 掉,因此界面展示的是MainActivity,如图1-3-3所示。可以看到MainActivity的TextView显示“欢迎学习EventBus",MainActivity成功地收到了SecondActivity发送的事件。
1.4 EventBus的黏性事件
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void onStickyEvent(MessageEvent event) {
if (event != null && event.getMessage() != null) {
tv_message.setText(event.getMessage());
}
}
btn_send_event.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MessageEvent event = new MessageEvent();
event.setMessage("EventBus黏性事件");
EventBus.getDefault().postSticky(event);
finish();
}
});
二 源码解析EventBus
2.1 EventBus构造方法
/** 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;
}
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
this调用了EventBus的另一个构造方法,如下所示:
EventBus(EventBusBuilder builder) {
// 以事件类型作为Key,Subscription的List集合作为Value的Map集合
subscriptionsByEventType = new HashMap<>();
// 订阅者作为Key,订阅事件的List集合作为Value的Map集合
typesBySubscriber = new HashMap<>();
// 黏性事件的Map集合
stickyEvents = new ConcurrentHashMap<>();
// Handler对象,用于线程间切换
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
// Runnable对象
backgroundPoster = new BackgroundPoster(this);
// Runnable对象
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;
}
2.2 订阅者注册
/**
* 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();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); // 1
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod); // 2
}
}
}
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 从缓存中获取SubscriberMethod集合
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); // 1
if (subscriberMethods != null) {
return subscriberMethods;
}
//ignoreGeneratedIndex是否忽略注解器生成的MyEventBusIndex,默认为false
if (ignoreGeneratedIndex) {
//通过反射获取subscriberMethods
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//通过注解器生成的MyEventBusIndex信息获取subscriberMethods,
//如果没有配置MyEventBusIndex,依然通过通过反射获取subscriberMethods
subscriberMethods = findUsingInfo(subscriberClass); // 3
}
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); // 2
return subscriberMethods;
}
}
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//创建和初始化FindState对象
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获取订阅者信息,没有配置MyEventBusIndex返回null
findState.subscriberInfo = getSubscriberInfo(findState); // 1
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); // 2
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//通过反射来查找订阅方法
findUsingReflectionInSingleClass(findState); // 3
}
//进入父类查找订阅方法
findState.moveToSuperclass();
}
//回收处理findState,并返回订阅方法的List集合
return getMethodsAndRelease(findState);
}
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(); // 1
} 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的注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//保存到findState对象当中
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");
}
}
}
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 获取订阅方法中的订阅事件
Class<?> eventType = subscriberMethod.eventType;
// 创建一个SubScription来保存订阅者和订阅方法
Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 1
//获取当前订阅事件中Subscription的List集合
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); // 2
if (subscriptions == null) {
//该事件对应的Subscription的List集合不存在,则重新创建并保存在subscriptionsByEventType中
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 判断订阅者是否已经被注册
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//将newSubscription按照订阅方法的优先级插入到subscriptions中
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); // 3
break;
}
}
//通过订阅者获取该订阅者所订阅事件的集合
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); // 4
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//将当前的订阅事件添加到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);
}
}
}
2.3 事件的发送
/** Posts the given event to the event bus. */
public void post(Object event) {
// PostingThreadState 保存着事件队列和线程状态信息
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;
}
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// eventInheritance 表示是否向上查找事件的父类,默认为true
if (eventInheritance) {
//获取所有事件并存放在List中,这里表示事件存在继承关系,向上查找事件的父类
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));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass); // 1
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) { // 2
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);
}
}
2.4 订阅者取消注册
取消注册则需要调用unregister方法,如下所示:
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); // 1
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType); // 2
}
typesBySubscriber.remove(subscriber); // 3
} 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); // 1
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的执行过程来它,他实际上就是一个典型的观察者模式。通过对事件的发布与订阅,实现了一种一对多的依赖关系,并有效的为我们事件的发送者与接收者之间进行了解耦。