EventBus(事件总线)
历史背景
它是由开源组织greenrobot贡献的Android事件发布/订阅的框架.
主要功能
通过解耦发布者和订阅者来简化Android中事件的传递(通俗来讲,就是一个人发事件的消息告诉另一个人该做什么,或者是某个人想将数据交给另一个人),这个事件传递既可用于四大组件之间的数据传递(也叫通信),也可以用于异步线程和主线程之间的通信.代替了传统的事件传递方式:Handler , BrocastReceiver , 接口回调,在Fragment , Activity , Service , 线程之间传递数据,执行方法.一句话:任何一个java类通可以用这个通讯
概念
事件(Event)
又可称为消息.其实就是一个对象.该对象可以是任意数据类型,不像Intent,Bundle传递数据一样局限.通常这个对象都是通过自定义一个事件类来实例化的
订阅者(Subscriber)
订阅某种事件类型的对象,也就是订阅接收事件信息的对象.当有发布者发布这类事件后,EventBus会执行订阅者的订阅函数,这个订阅函数俗称事件响应函数.订阅者通过注册(register)接口订阅某个事件类型,unregister进行接口退订.注意:订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为0.
发布者(Publisher)
发布某种事件的对象,通过post接口发布事件.
简单的使用案例
分别创建两个Activity,分别是SubscriberActivity(作为订阅者),PublisherActivity(作为发布者),PublisherActivity发布事件类型给SubscriberActivity接收,也就是发布者发布事件类型给订阅者接收,订阅者在订阅方法中做相应的处理.
创建事件类型,通常一个自定义类,这里我们命名为MyEvent
package jansonwang.example.com.myapplication;
/**
* Created by Jason Wang on 2017/5/22.
* 这是一个事件类型,它可以携带各种各样的数据类型
*/
public class MyEvent {
public String msg;
public MyEvent(String msg){
this.msg = msg;
}
}
创建SubscriberActivity(作为订阅者),并且注册订阅接口,自定义订阅函数,反注册订阅接口
package jansonwang.example.com.myapplication;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class SubscriberActivity extends AppCompatActivity {
private static final String TAG ="SubscriberActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//EventBus.getDefault();创建单个事件总线对象
EventBus.getDefault().register(this); //注册事件总线
}
public void start(View view) {
Intent intent = new Intent(this, PublisherActivity.class);
startActivity(intent);
}
/**
* 接收发布者的事件消息,
* ThreadMode.MAIN模式:无论发布者在子线程中还是主线程中发送事件信息,最后订阅者方法都会在主线程中执行,所以这种模式下不能在订阅者方法中进行耗时操作
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void receiveEventOnMain(MyEvent event) {
Log.d(TAG, "receiveEventOnMain: " + event.msg + " " + Thread.currentThread().getName());
Toast.makeText(SubscriberActivity.this, "ThreadMode.MAIN", Toast.LENGTH_SHORT).show();
}
/**
* 接收发布者的事件消息
* ThreadMode.POSTING模式:发布者在哪个线程中发布事件消息,订阅者方法就会在哪个线程中执行,所以这个模式下也不能进行耗时操作,会延迟分发
* @param event
*/
@Subscribe(threadMode = ThreadMode.POSTING)
public void receiveEventPosting(MyEvent event){
Log.d(TAG, "receiveEventPosting: " + event.msg + " " + Thread.currentThread().getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SubscriberActivity.this, "ThreadMode.POSTING", Toast.LENGTH_SHORT).show();
}
});
}
/**
* 接收发布者的事件消息
* ThreadMode.ASYNC模式:发布者无论在哪个线程中发布事件消息,订阅者方法都会自己重新创建一个子线程执行
* @param event
*/
@Subscribe(threadMode = ThreadMode.ASYNC)
public void receiveEventASYNC(MyEvent event){
Log.d(TAG, "receiveEventPosting: " + event.msg + " " + Thread.currentThread().getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SubscriberActivity.this, "ThreadMode.ASYNC", Toast.LENGTH_SHORT).show();
}
});
}
/**
* 接收发布者的事件消息
* ThreadMode.BACKGROUND模式:发布者如果在子线程中发布事件消息,订阅者方法就会在同一个子线程中执行;
* 发布者如果在主线程中发布事件消息,订阅者方法就会自己创建一个子线程执行
* @param event
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void receiveEventBACKGROUND(MyEvent event){
Log.d(TAG, "receiveEventPosting: " + event.msg + " " + Thread.currentThread().getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SubscriberActivity.this, "ThreadMode.BACKGROUND", Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//反注册事件总线
EventBus.getDefault().unregister(this);
}
}
创建PublisherActivity(作为发布者),并且发布事件
package jansonwang.example.com.myapplication;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import org.greenrobot.eventbus.EventBus;
/**
* Created by Jason Wang on 2017/5/22.
*/
public class PublisherActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_publisher);
}
/**
* 在主线程中发布消息
* @param view
*/
public void send1(View view) {
EventBus.getDefault().post(new MyEvent("发布者向订阅者发送事件消息"));
}
/**
* 在子线程中发布消息
* @param view
*/
public void send2(View view) {
new Thread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new MyEvent("发布者向订阅者发送事件消息"));
}
}).start();
}
}
*主要步骤:
1.订阅者注册订阅接口
//EventBus.getDefault();创建单个事件总线对象
EventBus.getDefault().register(订阅者类); //注册事件总线
2.在订阅者类中自定义订阅函数(记得在函数头上加引用,例如 @Subscribe(threadMode = ThreadMode.MAIN)),用来接收发布者发布事件类型,
/**
* 接收发布者的事件消息,
* ThreadMode.MAIN模式:无论发布者在子线程中还是主线程中发送事件信息,最后订阅者方法都会在主线程中执行,所以这种模式下不能在订阅者方法中进行耗时操作
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void receiveEventOnMain(MyEvent event) {
Log.d(TAG, "receiveEventOnMain: " + event.msg + " " + Thread.currentThread().getName());
Toast.makeText(SubscriberActivity.this, "ThreadMode.MAIN", Toast.LENGTH_SHORT).show();
}
/**
* 接收发布者的事件消息
* ThreadMode.POSTING模式:发布者在哪个线程中发布事件消息,订阅者方法就会在哪个线程中执行,所以这个模式下也不能进行耗时操作,会延迟分发
* @param event
*/
@Subscribe(threadMode = ThreadMode.POSTING)
public void receiveEventPosting(MyEvent event){
Log.d(TAG, "receiveEventPosting: " + event.msg + " " + Thread.currentThread().getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SubscriberActivity.this, "ThreadMode.POSTING", Toast.LENGTH_SHORT).show();
}
});
}
/**
* 接收发布者的事件消息
* ThreadMode.ASYNC模式:发布者无论在哪个线程中发布事件消息,订阅者方法都会自己重新创建一个子线程执行
* @param event
*/
@Subscribe(threadMode = ThreadMode.ASYNC)
public void receiveEventASYNC(MyEvent event){
Log.d(TAG, "receiveEventPosting: " + event.msg + " " + Thread.currentThread().getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SubscriberActivity.this, "ThreadMode.ASYNC", Toast.LENGTH_SHORT).show();
}
});
}
/**
* 接收发布者的事件消息
* ThreadMode.BACKGROUND模式:发布者如果在子线程中发布事件消息,订阅者方法就会在同一个子线程中执行;
* 发布者如果在主线程中发布事件消息,订阅者方法就会自己创建一个子线程执行
* @param event
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void receiveEventBACKGROUND(MyEvent event){
Log.d(TAG, "receiveEventPosting: " + event.msg + " " + Thread.currentThread().getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SubscriberActivity.this, "ThreadMode.BACKGROUND", Toast.LENGTH_SHORT).show();
}
});
}
3.创建一个类,作为要发布的事件类型
package jansonwang.example.com.myapplication;
/**
* Created by Jason Wang on 2017/5/22.
* 这是一个事件类型,它可以携带各种各样的数据类型
*/
public class 事件类型 {
public String msg;
public MyEvent(String msg){
this.msg = msg;
}
}
4.发布者发布事件类型
EventBus.getDefault().post(事件类型对象);
每个步骤的源码分析
EventBus.getDefault();//创建事件总线对象
这段代码采用的是单例模式:
```
//两个非空,一个加锁
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
```
下面是优化历史
//简单单例,当多线程时,还是会创建多个示例
public static EventBus getDefault() {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
return defaultInstance;
}
//加锁单例,每次调用都检查是否加锁
public static synchronized EventBus getDefault() {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
return defaultInstance;
}
//两个非空,一个加锁
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
EventBus.getDefault().register(this); //注册事件总线
下面是注册的源码
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//找到订阅者中所有的订阅方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//将订阅方法记录下来保存到对应事件的订阅列表中
//Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
subscribe(subscriber, subscriberMethod);
}
}
}
EventBus.getDefault().post(事件类型对象)
下面是发布者发布事件的源码:
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;
}
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
........
} else {
//发布对应事件类型的事件
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
.........
}
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;
}
........
}
return true;
}
......
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
//判断订阅方法的线程模型
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//POSTING线程模型下,直接反射调用订阅方法
invokeSubscriber(subscription, event);
break;
case MAIN:
//MAIN线程模型
if (isMainThread) {
//如果当前是主线程,则直接反射调用订阅方法
invokeSubscriber(subscription, event);
} else {
//如果当前不是主线程,则使用绑定主线程Looper的Handler在主线程调用订阅方法
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
//BACKGROUND线程模型
if (isMainThread) {
//如果当前是主线程,则在EventBus内部的线程池中执行
backgroundPoster.enqueue(subscription, event);
} else {
//如果当前是子线程,则直接在该子线程反射调用订阅方法
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//ASYNC线程模型
//直接在EventBus的线程池中执行
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}