前段时间被别人问到关于EventBus的原理,但我确实使用过,用起来也方便简单,一个注册,一个Post就能通知到所有的订阅者Subcriber,其实明明是知道一点点原理的,但是当时就是支支吾吾没有说,太low了,回来大概看了一眼EventBus的源码及实现原谅,现在想把看原代码的一些心得进行记录。OK,我们从Github上面了解一下官方如何介绍这个EventBus吧。

翻译:EventBus是一个事件发布/订阅总线,有效适用于Android系统平台。
EventBus...
.组件之间的通信更加简单
。针对在事件的发送者和订阅者之间进行解耦
。非常好的运用在Activitys、Fragments和后台线程
。避开了联系紧密易出错的依赖关系和容易出错生命周期
.使你的代码更加简洁
.快
.瘦(小于50K的jar包)
.有100,00,000+的app使用了EventBus
简单翻译就是这样一个意思,翻译不好请多担待,但是尽管翻译很差,但是大体的原理描述和工作是体现出来了。我是直接从Github上下载的最新的源代码进行研究的,在这里我想提出一个注意的地方,之前的旧一点的版本3.0之前的版本,订阅者的事件通知的方法都是通过开发者遵守命名约定,这样没有安全性,容易出错,很不方便开发,但是后来3.0开始使用注解的方式对事件的方法的声明。如下是之前的版本使用的命名约定的方式。
1、onEvent
2、onEventMainThread
3、onEventBackgroundThread
4、onEventAsync
现在最新版本订阅者的事件方法名称可以随意声明,只要在方法的上简单的加上一些相关的注解就可以了,而且注解是必须加上的,否则会抛出Runtime异常。OK,看看我们现在的做法:
很简单,就是一个单例设计代码,看看构造方法。
backgroundPoster : 那这个是什么呢,我们来看看代码。
</pre><pre code_snippet_id="1679566" snippet_file_name="blog_20160511_1_5619972" name="code" class="java">import org.greenrobot.eventbus.EventBus;
public class MainActivity extends Activity implements OnClickListener {
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
final Intent intent= new Intent(this,EventBusTestService.class);
startService(intent);
EventBus.getDefault().register(this);
mButton = (Button) findViewById(R.id.button1);
mButton.setOnClickListener(this);
}
@Subscribe(threadMode=ThreadMode.ASYNC)
public void onEventReceive(EventBusMsg msg){
Log.d("ZHG-EventBusTest","MainActivity.onEventReceive , msg = "+msg.msg +" , MainThreadID = "+this.getMainLooper().getThread().getId()+" , currentTreadID = "+Thread.currentThread().getId());
}
@Override
public void onClick(View view) {
switch (view.getId() ) {
case R.id.button1:
EventBus.getDefault().post(new EventBusMsg("Test Message!!!!"));
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
package com.example.eventbustest;
import org.greenrobot.eventbus.EventBus;
public class EventBusTestService extends Service {
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
EventBus.getDefault().register(this);
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode=ThreadMode.BACKGROUND)
public void onEventBusMsgReceive(EventBusMsg msg){
Log.d("ZHG-EventBusTest","EventBusTestService.onEventBusMsgReceive , msg = "+msg.msg +" , MainThreadID = "+this.getMainLooper().getThread().getId()+" , currentTreadID = "+Thread.currentThread().getId());
}
}
从上面的示例代码就能看出,最新的版本再也不用那么麻烦的去记住什么约定的方法怎么写,不用再去背了,现在只要自己命名成自己喜欢的方法名,然后简单的加上注解就行,而且还可以设置线程模式,比如是是否在主线程、子线程、是否异步等。
OK,上面是针对使用上的一些变化进行一个温馨提示,接下来直接奔入主题,看源代码把。
1. EventBus.getDefault();开始
入口EventBus.getDefault();开始,这里我还是很喜欢这样的静态单例对象获取方法名,我本人也很喜欢使用单例的时候,取名getDefault()。
/** 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);
}
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
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;
}
构造方法中创建了几个容器,用来装各种订阅者信息的,很关键的几个成员我们需要注意,mainThreadPoster 、backgroundPoster 、asyncPoster ,这个几个是后来post消息的时候,用的到的,就是利用他们将消息在不同的线程发送出去,达到在不同线程中执行的效果。
mainThreadPoster:很显然是一个自定义扩展后的Handler,在构造的时候传入的是主线的Looper,所以它是一个主线程的对应的Handler。
这里之间先看看这个Handler的代码吧:
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;
import android.os.Handler;
final class HandlerPoster extends Handler {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@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;
}
}
}
没错,就是传入一个MainThread的Looper,创建了一个主线程的Handler,毋庸置疑,通过他发送的事件消息,都是在主线中执行的。
backgroundPoster : 那这个是什么呢,我们来看看代码。
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;
import android.util.Log;
/**
* Posts events in background.
*
* @author Markus
*/
final class BackgroundPoster implements Runnable {