EventBus的使用与深入学习
注意:以下分析都是基于EventBus 3.0x
转载请注明出处:http://blog.csdn.net/evan_man/article/details/51328628
简单介绍
EventBus是一个用于简化Andorid、Fragment、Threads、Service之间信息传递的一个发布/订阅事件集。
传统的Android组件之间的通信方式有:Activity之间使用Intent;Service向Activity发送broadcast;Fragment和Activity之间相互持有对方的引用(随后可以调用对方的相关方法进行事件传递)。传统的事件传递的问题在于:通信方式没有实现解耦,是硬编码在组件中的。组件一旦发生修改,对应的通信方式就需要跟着修改。其实不管什么场景下,我们最好能够使得自己编写的代码最大限度的解耦,这是一个很好的习惯,避免无用功,提高代码利用率。
使用EventBus的建议:
并不建议将应用中所有的事件都通过EventBus进行发送,尤其对于一对一的组件之间通信,建议不要使用EventBus。EventBus的使用场景更像是一种广播,当我们向EventBus发送一个事件,则该事件将会传递给多个该事件的订阅者,比如Service向Activities发送事件。跟LoacalBroadCast有点近似
在Activity和Fragment中使用EventBus时,要注意在组件的生命周期开始时registered EventBus,在生命周期结束时unregistered EventBus。否则容易导致OOM;
使用EventBus的好处在于:
简化组件之间的通信方式
让业务代码更加简洁(但是需要配合相应注解进行使用)
可以指定事件处理方法的执行线程,和订阅者的优先级(跟广播类似)
足够的稳定,已经被很多Android应用使用,你绝对不是第一个吃螃蟹的人
EventBus实现了解耦,事件的创建和分发由EventBus管理,工作在一个单独的线程。EventBus的工作原理如下图:
基本使用
一、引入依赖
[java] view plain copy
在CODE上查看代码片派生到我的代码片
compile 'org.greenrobot:eventbus:3.0.0'
provided 'org.glassfish:javax.annotation:10.0-b28' //解决获取不到@Subscribe注解的问题
二、定义事件
[java] view plain copy
在CODE上查看代码片派生到我的代码片
public class IntentServiceResult {
int mResult;
String mResultValue;
IntentServiceResult(int resultCode, String resultValue) {
mResult = resultCode;
mResultValue = resultValue;
}
public int getResult() { return mResult; }
public String getResultValue() { return mResultValue; }
}
三、注册EventBus
[java] view plain copy
在CODE上查看代码片派生到我的代码片
public class MainActivity extends AppCompatActivity {
@Override protected void onPause() {
super.onPause();
EventBus.getDefault().unregister(this); //注:为了后面分析的方便我们对进行注册的对象取名订阅者,如这里的MainActivity.this对象
}
@Override protected void onResume() {
super.onResume();
EventBus.getDefault().register(this);
}
}
四、发布事件
[java] view plain copy
在CODE上查看代码片派生到我的代码片
EventBus.getDefault().post(new IntentServiceResult(24, "done!!"));
五、创建事件处理方法
[java] view plain copy
在CODE上查看代码片派生到我的代码片
public class MainActivity extends AppCompatActivity {
@Subscribe(threadMode = ThreadMode.MAIN)
public void doThis(IntentServiceResult intentServiceResult) {
Toast.makeText(this, intentServiceResult.getResultValue(), Toast.LENGTH_SHORT).show();
}
}
此处的threadMode = ThreadMode.MAIN表明下面的事件处理方法在 ThreadMode.MAIN线程中执行,默认会在EventBus的工作线程中执行(发送post事件方法所在的线程)。
ThreadMode.POSTING:在和发送事件相同的线程中执行。默认的线程模式
ThreadMode.MAIN:Android的UI线程中执行。
ThreadMode.BACKGROUND:交给EventBus的一条幕后线程去执行,注意EventBus中只有一个这样的幕后线程,所以的异步方法会在这条线程中顺序执行。要求事件处理方法不要耗时太长!
ThreadMode.ASYNC:在一个单独的线程中执行,总是和发送事件的线程以及UI线程相隔离。将每个这样的事件处理方法扔到一个线程池申请一条线程进行处理。对于网络请求等可以使用这种模式!
源码学习
学习之前问问自己目的是什么,这次学习我们只是想了解以下内容
EventBus内部存储有哪些域,我们通过getDefault方法获取到的是不是它的一个单例?
EventBus的unregister和register方法内部是怎样的业务逻辑。是简单的将该对象添加一个集合,然后像Retrofit那样为每个使用了@Susbcribe标注的Method创建一个ServiceMethod?
EventBus的post方法内部的业务逻辑、是去遍历调用注册了该事件的方法来处理该事件?如何快速的找到注册了该事件的方法(Map)?
使用了@Subscribe(threadMode = ThreadMode.MAIN)标注的方法为何会在指定的线程中执行?
EventBus.class
Fields:
[java] view plain copy
在CODE上查看代码片派生到我的代码片
/*****下面的数据在EventBus自身构造器中被创建*****/
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//以事件类型为key,该事件对应的Subscription集合为value;此处使用CopyOnWrite的好处在于它是线程安全的集合,同一时间只有一个线程可以修改该集合的数据!
private final Map<Object, List<Class<?>>> typesBySubscriber;
//以注册EventBus的对象(该对象会接收EventBus发来的事件)为key,该对象接收的事件类型为Value
private final Map<Class<?>, Object> stickyEvents;
//sticky在@Subscribe标注时设置(sticky=true), sticky默认是false;直译过来是粘性事件、说人话那就是该类事件会一直被EventBus所保存,除非用户手动删除!同时从Map<Class<?>, Object>可以看出任何类型的事件只会保存一个对应的实例!
private final HandlerPoster mainThreadPoster;
//对应ThreadMode.MAIN模式,是一个继承Handler的类
private final BackgroundPoster backgroundPoster;
//对应ThreadMode.BACKGROUND模式,是一个实现了Runnable方法的类
private final AsyncPoster asyncPoster;
//对应ThreadMode.ASYNC模式,是一个实现了Runnable方法的类
/*****下面的数据都是来自EventBusBuilder*****/
private final int indexCount;
//一般情况为0,是EventBuilder.subscriberInfoIndexes.size()的值
private final SubscriberMethodFinder subscriberMethodFinder;
//订阅方法查找器负责对目标对象中使用了@Subscribe进行标注的方法进行解析得到一个SubscriberMethod对象
private final boolean logSubscriberExceptions;
//一般情况为true
private final boolean logNoSubscriberMessages;
//一般情况为true
private final boolean sendSubscriberExceptionEvent;
//一般情况为true
private final boolean sendNoSubscriberEvent;
//一般情况为true
private final boolean throwSubscriberException;
//一般情况为false
private final boolean eventInheritance;
//一般情况为true,事件是否具有传递性的标志位
private final ExecutorService executorService;
//执行器,对应一个Executors.newCachedThreadPool()线程池
/*****下面的对象创建时初始化或者类加载时初始化*****/
static volatile EventBus defaultInstance;
//单例
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
//创建EventBus对象的Builder
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
//以事件类型为key,其对应的所以父类、实现的所有接口及接口父类为value
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override protected PostingThreadState initialValue() { return new PostingThreadState(); }
};
//当前线程的PostingThreadState对象,之后通过get方法获取该对象
接着我们看看使用getDefault方法得到的EventBus对象
getDefault()@EventBus.class
[java] view plain copy
在CODE上查看代码片派生到我的代码片
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {defaultInstance = new EventBus();}
}
}
return defaultInstance;
}
一个很经典的单例模式,调用EventBus的构造器创建EventBus对象;
EventBus()@EventBus.class
[java] view plain copy
在CODE上查看代码片派生到我的代码片
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; //一般情况为0
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//一般情况参数为null、false、false;该对象我们后面会介绍
logSubscriberExceptions = builder.logSubscriberExceptions; //一般情况为true
logNoSubscriberMessages = builder.logNoSubscriberMessages; //一般情况为true
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; //一般情况为true
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;//一般情况为true
throwSubscriberException = builder.throwSubscriberException; //一般情况为false
eventInheritance = builder.eventInheritance; //一般情况为true
executorService = builder.executorService; //一个newCachedThreadPool()
}
EventBusBuilder.class
Fields:
[java] view plain copy
在CODE上查看代码片派生到我的代码片
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
List<SubscriberInfoIndex> subscriberInfoIndexes;
boolean strictMethodVerification;
boolean ignoreGeneratedIndex;
boolean logSubscriberExceptions = true;
boolean logNoSubscriberMessages = true;
boolean sendSubscriberExceptionEvent = true;
boolean sendNoSubscriberEvent = true;
boolean throwSubscriberException;
boolean eventInheritance = true;
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
//总结:eventInheritance、logXX和sendXX全为true;其它全为false;
到此为止我们分析了调用getDefault方法得到的EventBus对象;
该对象存储有如下两个集合
Map