目录
概念
EventBus:是一个Android事件发布/订阅框架,通过解耦发布者与订阅者的方式,大大的简化了Activity与Activity,Activity与Fragment,Fragment与Fragment等之间的数据传递,从而使得代码更简洁明了。
使用
1,配置
- 打开App的build.gradle,在dependencies中添加最新的EventBus依赖:
3.0以下版本的AndroidStudio : compile 'org.greenrobot:eventbus:3.1.1'
3.0及以上版本的AndroidStudio : implementation 'org.greenrobot:eventbus:3.1.1'>- 索引加速模式(在AndroidStudio3.1.3上配置成功,在2.2.2版本上使用网上的两种方案均无MyEventBusIndex文件生成) 。成功配置的步骤如下(针对AndroidStudio3.1.3)
1,在app的build.gradle文件的dependencies中添加:
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
2,在app的build.gradle文件的defaultConfig中添加:(com.learn.study:当前的包名,可以自己配置)
javaCompileOptions {
annotationProcessorOptions {
arguments = [ eventBusIndex : 'com.learn.study.MyEventBusIndex' ]
}
}
3,rebuiid项目后在app的build/generated/source/apt/debug中找到:MyEventBusIndex文件
2,注册与注销
//注册(一般在Activity或Fragment的onCreate中进行)
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
//注销(一般是在Activity或Fragment的onDestory中进行)
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
//补充(如果使用了索引加速):在Application中配置:
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
3,接收事件
//3.0以后方法名可以任意,但必须加上@Subscribe的标识,同时设置参数为:
threadMode:当前接收事件的执行线程
sticky:是否接收粘性事件;
priority:设置优先级
方法的参数与发送的数据类型一致,必须为对象类型,如:必须使用Integer而不能使用int
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 0)
public void getMainData(Integer number) {
Log.d(TAG, "ThreadMode : getMainData: " + number + " ;; " + Thread.currentThread().getName());
}
四种线程模型(ThreadMode:定义线程类型的枚举类)说明:
- POSTING : 在当前发送的线程中执行(不用切换线程,最轻量级)
- MAIN:在主线程中执行
- MAIN_ORDERED:在主线程中执行,但事件始终排队等候确保调用为非阻塞(不常用)
- BACKGROUND:后台线程,当在UI线程时中发布时才会新建一个后台线程执行
- ASYNC:交给线程池来管理,直接通过asyncPoster调度。
4,发送事件
//发送普通事件
EventBus.getDefault().post(10);
//发送粘性事件
EventBus.getDefault().postSticky(20);
5,注意事项
1,有注册必须有注销,保证一一对应,同时调用的生命周期方法也对应
2,注册页面必须有接收方法,主要是需要识别到有Subscribe的注解,发送界面不需要注册。
3,同一个事件可以定义多个接收,参数必须是对象类型。如:发送的是int但接收参数必须为Interger
4,使用普通的post发送事件时,必须先注册才能收到。而postSticky可以在发送后注册也能收到
//1,验证普通事件与粘性事件的发送与注册顺序
private void testEventBus() {
EventBus.getDefault().postSticky(20);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 0)
public void getMainData(Integer number) {
Log.d(TAG, "ThreadMode : getMainData: " + number + " ;; " + Thread.currentThread().getName());
}
//打印结果:(即事件能够收到并处理)
10-24 21:13:52.574 5913-5913/com.learn.study D/MainActivity: ThreadMode : getMainData: 20 ;; main
private void testEventBus() {
EventBus.getDefault().post(10);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 0)
public void getMainData(Integer number) {
Log.d(TAG, "ThreadMode : getMainData: " + number + " ;; " + Thread.currentThread().getName());
}
//无打印,即事件未接收
//2,验证线程模型
@Subscribe(threadMode = ThreadMode.MAIN)
public void getMainData(Integer number) {
Log.d(TAG, "ThreadMode : getMainData: " + number + " ;; " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void getThreadData(Integer number) {
Log.d(TAG, "ThreadMode : getThreadData: " + number + " ;; " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.POSTING)
public void getPostData(Integer number) {
Log.d(TAG, "ThreadMode : getPostData: " + number + " ;; " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void getAsyncData(Integer number) {
Log.d(TAG, "ThreadMode : getAsyncData: " + number + " ;; " + Thread.currentThread().getName());
}
EventBus.getDefault().post(10);
Log.d("MainActivity", "ThreadMode : sendData :" + Thread.currentThread().getName());
//在主线程中发送结果打印:
10-24 21:28:19.490 6837-6837/com.learn.study D/MainActivity: ThreadMode : getMainData: 10 ;; main
ThreadMode : getPostData: 10 ;; main
10-24 21:28:19.491 6837-7309/com.learn.study D/MainActivity: ThreadMode : getThreadData: 10 ;; pool-1-thread-1
10-24 21:28:19.491 6837-6837/com.learn.study D/MainActivity: ThreadMode : sendData :main
10-24 21:28:19.491 6837-7310/com.learn.study D/MainActivity: ThreadMode : getAsyncData: 10 ;; pool-1-thread-2
//在子线程中发送结果打印:
10-24 21:33:22.969 7800-7859/com.learn.study D/MainActivity: ThreadMode : getThreadData: 10 ;; Thread-4
ThreadMode : getPostData: 10 ;; Thread-4
10-24 21:33:22.970 7800-7860/com.learn.study D/MainActivity: ThreadMode : getAsyncData: 10 ;; pool-1-thread-1
10-24 21:33:22.970 7800-7859/com.learn.study D/MainActivity: ThreadMode : sendData :Thread-4
10-24 21:33:23.028 7800-7800/com.learn.study D/MainActivity: ThreadMode : getMainData: 10 ;; main
//3,验证接收事件的优先级(相同的线程中才存在优先级问题,同时拦截才有效果)
10-24 22:04:43.762 10532-10596/com.learn.study D/MainActivity: ThreadMode : getThreadData: 10 ;; Thread-4;; 优先级:6
ThreadMode : getPostData: 10 ;; Thread-4;; 优先级:3
10-24 22:04:43.763 10532-10596/com.learn.study D/MainActivity: ThreadMode : sendData :Thread-4
10-24 22:04:43.763 10532-10597/com.learn.study D/MainActivity: ThreadMode : getAsyncData: 10 ;; pool-1-thread-1;; 优先级:0
10-24 22:04:43.810 10532-10532/com.learn.study D/MainActivity: ThreadMode : getMainData: 10 ;; main;; 优先级:10
ThreadMode : getMain1Data: 10 ;; main;; 优先级:7
原理(针对3.1.1版本的源码)
1,注册的流程
//1,使用双重校验的单例创建对象:EventBus.getDefault()
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
//2,register()调用注册的方法
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
//查找当前注册类所有的接收方法
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
//具体实现查找接收方法:
List findSubscriberMethods(Class> subscriberClass) {
//1,从Map集合METHOD_CACHE(键:注册的类class对象,值:当前注册类里面的接收方法)中查找方法,如果查询到方法则直接返回方法集合List,否则重新获取
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
//2,忽视索引加速的方式,直接使用反射的方式获取的注册类下的所有接受方法:最后还是调用findUsingReflectionInSingleClass()方法
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//3,获取到注册类里面的接收方法
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;
}
}
private List findUsingInfo(Class> subscriberClass) {
//1,这里存在一个查找状态池:FIND_STATE_POOL,大小为4,减少对象的创建。
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//2,查找注册类的接受方法,如果添加了索引加速,而返回接受方法,否则返回null
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//未添加索引加速时使用反射获取接受方法
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
//使用索引加速获取方法
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
//使用了索引加速则info返回索引的接收方法,否则返回null
return info;
}
}
}
return null;
}
//使用反射获取接收方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//1,使用反射先获取到注册类里面的所有方法
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;
}
//2,遍历所有方法,找到接收事件的方法
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) {
//3,通过获取方法上的注解Subscribe来区分接收事件的方法.
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
//4,将接收事件的方法信息添加到查询状态的对象中
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");
}
}
}
//查找完成接收事件的方法后,调用subscribe(),将注册类,接收方法,接收事件的类型等添加到对应的Map集合中进行保存,避免相应信息每次获取
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList 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();
//根据接收事件的优先级,将订阅事件存放到subscriptionsByEventType集合中
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, 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).
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, 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,注销流程
EventBus.getDefault().unregister(this);
//1,与注册相同,使用单例获取到EventBus对象.
public synchronized void unregister(Object subscriber) {
//typesBySubscriber这是一个Map集合,键为:注册的类,值为当前类中处理的事件类型集合
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
//从存放注册类与事件类型的对照集合中移除注册类,这样也可以防止对象引用无法释放.
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
//subscriptionsByEventType这也是一个Map集合,键:事件类型,值:事件类型对应的接收方法.
//Subscription:将注册类与接收方法封装为了一个数据结构
List 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--;
}
}
}
}
3,发布事件
//发送粘性事件
public void postSticky(Object event) {
synchronized (stickyEvents) {
//将粘性事件存入stickyEvents集合中,键为:事件类型,值:事件的具体值
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
//发送普通事件
public void post(Object event) {
//使用ThreadLocal存放当前线程状态对象:PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
List
4,索引加速的原理
在编译期生成类用来记录所有的接收事件方法,将运行期的反射提前到编译期,避免了运行期使用反射增加的性能开销。编译期生成的类如下:
public class MyEventBusIndex implements SubscriberInfoIndex {
//用来存放所有的接收事件方法,避免后面需要通过反射获取,减小运行的性能开销
private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("getMainData", Integer.class, ThreadMode.MAIN, 10, false),
new SubscriberMethodInfo("getMain2Data", Integer.class, ThreadMode.MAIN, 7, false),
new SubscriberMethodInfo("getThreadData", Integer.class, ThreadMode.BACKGROUND, 6, false),
new SubscriberMethodInfo("getPostData", Integer.class, ThreadMode.POSTING, 3, false),
new SubscriberMethodInfo("getAsyncData", Integer.class, ThreadMode.ASYNC),
}));
}
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
}
参考:
https://www.cnblogs.com/bugly/p/5475034.html