EventBus3原理分析.docx
- 文档编号:26127074
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:21
- 大小:312.06KB
EventBus3原理分析.docx
《EventBus3原理分析.docx》由会员分享,可在线阅读,更多相关《EventBus3原理分析.docx(21页珍藏版)》请在冰豆网上搜索。
EventBus3原理分析
EventBus3原理分析
在接入微信支付的时候,为了传递支付结果的值,就使用了EventBus,那时候只是简单了解了EventBus的使用,现在有时间就来深入研究一下EventBus的实现原理和源码。
EventBus的介绍
可能有部分同学还没有使用过EventBus,那我们首先来了解一下EventBus的作用。
EventBus是一款基于观察者模式的事件发布/订阅框架。
简化了应用程序内各组件间、组件与后台线程间的通讯。
优点是开销小,优化更优雅,以及将发送者和接受者解耦。
如果Activity和Activity进行交互大家都知道,而Fragment和Fragment之间通讯写法五花八门、跨线程/跨界面我们就开始头疼了,那么我们来学习一下EventBus3。
EventBus的主要三要素:
Event:
事件。
可以是任意类型的对象。
Subscriber:
事件订阅者。
在EventBus3之前消息处理通过在onEvent、onEventMainTain、onEventBackgroundThread和onEventAsync,他们代表着四种线程模型。
在EventBus3之后,事件处理的方法可以按照自己需要命名,但是需要添加一个注解@Subscribe和指定线程模型。
Publisher:
事件发布者。
可以在任意线程和位置发送事件。
EventBus的四种ThreadMode
POSTING(默认):
如果使用事件处理函数指定了线程模型为POSTING,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。
在线程模型为POSTING的事件处理函数中精良避免执行耗时操作,因为它会阻塞事件的传递。
MAIN:
事件的处理会在UI线程中执行,事件处理的时间不能太长,可能出现ANR。
BACKFROUND:
如果事件在UI线程发布的,那么该线程就会在新的线程中运行,如果事件本来就是子线程发布的,那么该事件处理函数直接在发布事件的线程中执行,在此事件处理函数中禁止进行UI更新操作。
ASYNC:
无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行,同样,此事件处理函数中禁止进行UI更新操作。
EventBus的基本用法
AndroidStudio配置Gradle:
compile'org.greenrobot:
eventbus:
3.0.0'
定义一个事件类
publicclassEventBusEvent{
privateStringmessage;
publicEventBusEvent(Stringmessage){
this.message=message;
}
publicStringgetMessage(){
returnmessage;
}
publicvoidsetMessage(Stringmessage){
this.message=message;
}
}
注册事件
EventBus.getDefault().register(this);
发送事件
EventBus.getDefault().post(message);
处理事件
@Subscribe(threadMode=ThreadMode.BACKGROUND)
publicvoidXXXXXX(EventBusEventmessage){
}
取消事件订阅
EventBus.getDefault().unregister(this);
EventBus源码分析
我们首先从开头注册开始分析EventBus.getDefault()其实就是一个单例。
/**Conveniencesingletonforappsusingaprocess-wideEventBusinstance.*/
publicstaticEventBusgetDefault(){
if(defaultInstance==null){
synchronized(EventBus.class){
if(defaultInstance==null){
defaultInstance=newEventBus();
}
}
}
returndefaultInstance;
}
使用双重判断方式,防止并发。
接着看看newEventBus()。
/**
*CreatesanewEventBusinstance;eachinstanceisaseparatescopeinwhicheventsaredelivered.Tousea
*centralbus,consider{@link#getDefault()}.
*/
publicEventBus(){
this(DEFAULT_BUILDER);
}
所在的参DEFAULT_BUILDER,在EventBus.class的全局进行初始化:
privatestaticfinalEventBusBuilderDEFAULT_BUILDER=newEventBusBuilder();
在看一下this调用了EventBus的另一构造方法。
使用的是现在常用的Builder模式:
EventBus(EventBusBuilderbuilder){
subscriptionsByEventType=newHashMap<>();
typesBySubscriber=newHashMap<>();
stickyEvents=newConcurrentHashMap<>();
mainThreadPoster=newHandlerPoster(this,Looper.getMainLooper(),10);
backgroundPoster=newBackgroundPoster(this);
asyncPoster=newAsyncPoster(this);
···//一系列builder赋值
}
我们得到EventBus对象后,我们就可以调用register方法。
publicvoidregister(Objectsubscriber){
Class
>subscriberClass=subscriber.getClass();
List
synchronized(this){
for(SubscriberMethodsubscriberMethod:
subscriberMethods){
subscribe(subscriber,subscriberMethod);
}
}
}
先是获取订阅者的class,接着交给subscriberMethodFinder.findSubscriberMethods()处理,返回的是List类型的集合,对于SubscriberMethod类中,主要是用于保存订阅方法的Method对象,线程模式、事件类型、优先级、是否是粘性事件等属性。
下面我们直接看看这个方法:
List
>subscriberClass){
//从缓存中取出subscriberMethods,如果有则直接返回该已取的方法
List
if(subscriberMethods!
=null){
returnsubscriberMethods;
}
//从EventBusBuilder中可知,ignoreGeneratedIndex一般为false
if(ignoreGeneratedIndex){
subscriberMethods=findUsingReflection(subscriberClass);
}else{
subscriberMethods=findUsingInfo(subscriberClass);
}
if(subscriberMethods.isEmpty()){
thrownewEventBusException("Subscriber"+subscriberClass
+"anditssuperclasseshavenopublicmethodswiththe@Subscribeannotation");
}else{
//将获取到的subscriberMethods放入缓存中
METHOD_CACHE.put(subscriberClass,subscriberMethods);
returnsubscriberMethods;
}
}
首先从缓存中查找,如果缓存没有会根据ignoreGeneratedIndex选择如何查找订阅方法,ignoreGeneratedIndex默认false,可以通过EventBusBuilder来设置它的值。
我们一般是通过getDefault()获取默认的EventBus对象,也就ignoreGeneratedIndex为false的情况,这时调用的是
findUsingInfo(),我们接着看看这个方法:
privateList
>subscriberClass){
//准备一个findstate,该findState保存了订阅者类信息
FindStatefindState=prepareFindState();
//对FindState初始化
findState.initForSubscriber(subscriberClass);
while(findState.clazz!
=null){
findState.subscriberInfo=getSubscriberInfo(findState);
if(findState.subscriberInfo!
=null){
SubscriberMethod[]array=findState.subscriberInfo.getSubscriberMethods();
for(SubscriberMethodsubscriberMethod:
array){
if(findState.checkAdd(subscriberMethod.method,subscriberMethod.eventType)){
findState.subscriberMethods.add(subscriberMethod);
}
}
}else{
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
returngetMethodsAndRelease(findState);
}
上面用到了FindState这个内部类是保存订阅者的信息,我们看看它的内部结构:
staticclassFindState{
finalList
finalMap
finalMap
finalStringBuildermethodKeyBuilder=newStringBuilder(128);
Class
>subscriberClass;
Class
>clazz;
booleanskipSuperClasses;
SubscriberInfosubscriberInfo;
voidinitForSubscriber(Class
>subscriberClass){
this.subscriberClass=clazz=subscriberClass;
skipSuperClasses=false;
subscriberInfo=null;
}
···
}
可以看出,该内部类保存了订阅者及其订阅方法的信息,用Map一一对应来保存,接着利用initForSubscriber()进行初始化,在初始化的时候subscriberInfo设置为null,所以SubscriberMethodFinder的findUsingInfo()里面在初始化后会调用findUsingReflectionInSingleClass()方法。
那么我们接着看看这个方法:
privatevoidfindUsingReflectionInSingleClass(FindStatefindState){
Method[]methods;
try{
//ThisisfasterthangetMethods,especiallywhensubscribersarefatclasseslikeActivities
methods=findState.clazz.getDeclaredMethods();
}catch(Throwableth){
//Workaroundforjava.lang.NoClassDefFoundError,see
methods=findState.clazz.getMethods();
findState.skipSuperClasses=true;
}
for(Methodmethod:
methods){
intmodifiers=method.getModifiers();
if((modifiers&Modifier.PUBLIC)!
=0&&(modifiers&MODIFIERS_IGNORE)==0){
Class
>[]parameterTypes=method.getParameterTypes();
if(parameterTypes.length==1){
//获取该方法的@Subscribe注解
SubscribesubscribeAnnotation=method.getAnnotation(Subscribe.class);
if(subscribeAnnotation!
=null){
Class
>eventType=parameterTypes[0];
if(findState.checkAdd(method,eventType)){
ThreadModethreadMode=subscribeAnnotation.threadMode();
findState.subscriberMethods.add(newSubscriberMethod(method,eventType,threadMode,
subscribeAnnotation.priority(),subscribeAnnotation.sticky()));
}
}
}elseif(strictMethodVerification&&method.isAnnotationPresent(Subscribe.class)){
StringmethodName=method.getDeclaringClass().getName()+"."+method.getName();
thrownewEventBusException("@Subscribemethod"+methodName+
"musthaveexactly1parameterbuthas"+parameterTypes.length);
}
}elseif(strictMethodVerification&&method.isAnnotationPresent(Subscribe.class)){
StringmethodName=method.getDeclaringClass().getName()+"."+method.getName();
thrownewEventBusException(methodName+
"isaillegal@Subscribemethod:
mustbepublic,non-static,andnon-abstract");
}
}
}
这里主要是使用了Java的反射和对注解的解析。
首先是通过反射来获取订阅者中的所有方法,并根据方法的类型、参数和注解来找到订阅方法。
找到订阅方法后将订阅方法相关信息保存到FindState中。
通过上述的方法,把SubscriberMethods不断逐层返回,返回到EventBus.register(),并开始遍历每一个订阅方法,并调用subscribe(subscriber,subscriberMethod)方法对所有订阅方法进行注册,那么我们接着去这方法的实现:
//Mustbecalledinsynchronizedblock
privatevoidsubscribe(Objectsubscriber,SubscriberMethodsubscriberMethod){
Class
>eventType=subscriberMethod.eventType;
//根据订阅者和订阅方法构造一个订阅事件
SubscriptionnewSubscription=newSubscription(subscriber,subscriberMethod);
//获取当前订阅事件中的Subscription的集合
CopyOnWriteArrayList
//该事件对应的Subscription的集合不存在,则重新创建并保存在subscriptionsByEventType中
if(subscriptions==null){
subscriptions=newCopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType,subscriptions);
}else{
//订阅者已经注册则抛出一个EventBusException异常
if(subscriptions.contains(newSubscription)){
thrownewEventBusException("Subscriber"+subscriber.getClass()+"alreadyregisteredtoevent"
+eventType);
}
}
//遍历订阅事件,根据优先级来设置放进subscriptions,优先级高的会先被通知
intsize=subscriptions.size();
for(inti=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=newArrayList<>(); //把订阅者、事件放进typesBySubscriber这个Map中 typesBySubscriber.put(subscriber,subscribedEvents); } //将当前的订阅事件添加到subscribedEvents中 subscribedEvents.add(eventType); if(subscriberMethod.sticky){ if(eventInheritance){ //粘性事件处理 //ExistingstickyeventsofallsubclassesofeventTypehavetobeconsidered. //Note: Iteratingoveralleventsmaybeinefficientwithlotsofstickyevents, //thusdatastructureshouldbechangedtoallowamoreefficientlookup //(e.g.anadditionalmapstoringsubclassesofsuperclasses: Class->List Set >,Object>>entries=stickyEvents.entrySet(); for(Map.Entry >,Object>entry: entries){ Class >candidateEventType=entry.getKey(); if(eventType.isAssignableFrom(candidateEventType)){ ObjectstickyEvent=entry.getValue(); checkPostStickyEventToSubscription(newSubscrip
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- EventBus3 原理 分析