Android事件总线框架Otto源码解析一(Bus的构造过程及在使用注解@Subscribe时的注册过程)

本文主要是介绍Android事件总线框架Otto源码解析一(Bus的构造过程及在使用注解@Subscribe时的注册过程),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 说明:本文的解析过程并不只是简单的讲解框架中各个方法的调用逻辑、程序的执行过程,而是依赖于示例代码,结合了具体的的示例程序的执行流程,有助于更好的理解。

有关Otto的使用方法参见另一篇文章: Android事件总线框架Otto使用介绍

package com.example.myotto;import android.content.Context;
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.Button;
import android.widget.TextView;import com.squareup.otto.Subscribe;public class MainActivity extends AppCompatActivity {private static final String TAG = MainActivity.class.getSimpleName();private Button mBtnJumpToPost, mBtnJumpToProduce, mBtnJumpToMainActivity;private TextView mTvMessage, mTvMessageUpdate;public static void start(Context context) {context.startActivity(new Intent(context, MainActivity.class));}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mTvMessage = (TextView) this.findViewById(R.id.tv_message);mTvMessageUpdate = (TextView) this.findViewById(R.id.tv_message_update);mBtnJumpToPost = (Button) this.findViewById(R.id.btn_jump_to_post);mBtnJumpToMainActivity = (Button) this.findViewById(R.id.btn_jump_to_main_activity);mBtnJumpToProduce = (Button) this.findViewById(R.id.btn_jump_to_produce);mBtnJumpToPost.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {PostActivity.start(MainActivity.this);}});mBtnJumpToProduce.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ProduceActivity.start(MainActivity.this);}});mBtnJumpToMainActivity.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {MainActivity.start(MainActivity.this);}});Log.i(TAG, "method:onCreate#this#hashCode=" + this.hashCode());OttoBus.getInstance().register(this);}@Subscribepublic void refreshMessage(EventData eventData) {Log.i(TAG, "method:Subscribe#refreshMessage#eventData#hashCode=" + eventData.hashCode());Log.i(TAG, "method:Subscribe#refreshMessage#eventData=" + eventData);mTvMessage.setText(eventData.getUserName() + ":\n\n" + eventData.getMessage());}@Subscribepublic void updateMessage(EventData eventData) {Log.i(TAG, "method:updateMessage#updateMessage#eventData#hashCode=" + eventData.hashCode());Log.i(TAG, "method:Subscribe#updateMessage#eventData=" + eventData);mTvMessageUpdate.setText(eventData.getUserName() + ":\n\n" + eventData.getMessage());}@Overrideprotected void onDestroy() {super.onDestroy();OttoBus.getInstance().unregister(this);}
}

 Bus的构造过程:

Otto源码中并没有提供Bus的单例实现,我们可以在使用前自行构造一个单例模式。

package com.example.myotto;import com.squareup.otto.Bus;public class OttoBus extends Bus {private volatile static OttoBus bus;private OttoBus() {}public static OttoBus getInstance() {if (bus == null) {synchronized (OttoBus.class) {if (bus == null) {bus = new OttoBus();}}}return bus;}
}

在源码中Bus类的无参构造方法,实际上最终还是调用了 Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder)这个构造方法,并且在调用过程中注入了一些默认的参数 :DEFAULT_IDENTIFIER 、 ThreadEnforcer.MAIN 和HandlerFinder.ANNOTATED。

public class Bus {public static final String DEFAULT_IDENTIFIER = "default";/** All registered event handlers, indexed by event type. */private final ConcurrentMap<Class<?>, Set<EventHandler>> handlersByType =new ConcurrentHashMap<Class<?>, Set<EventHandler>>();/** All registered event producers, index by event type. */private final ConcurrentMap<Class<?>, EventProducer> producersByType =new ConcurrentHashMap<Class<?>, EventProducer>();/** Identifier used to differentiate the event bus instance. */private final String identifier;/** Thread enforcer for register, unregister, and posting events. */private final ThreadEnforcer enforcer;/** Used to find handler methods in register and unregister. */private final HandlerFinder handlerFinder;/** Queues of events for the current thread to dispatch. */private final ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>> eventsToDispatch =new ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>() {@Override protected ConcurrentLinkedQueue<EventWithHandler> initialValue() {return new ConcurrentLinkedQueue<EventWithHandler>();}};/** True if the current thread is currently dispatching an event. */private final ThreadLocal<Boolean> isDispatching = new ThreadLocal<Boolean>() {@Override protected Boolean initialValue() {return false;}};public Bus() {this(DEFAULT_IDENTIFIER);}public Bus(String identifier) {this(ThreadEnforcer.MAIN, identifier);}public Bus(ThreadEnforcer enforcer) {this(enforcer, DEFAULT_IDENTIFIER);}public Bus(ThreadEnforcer enforcer, String identifier) {this(enforcer, identifier, HandlerFinder.ANNOTATED);}Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder) {this.enforcer =  enforcer;this.identifier = identifier;this.handlerFinder = handlerFinder;}.......省略.......}

根据具体的示例分析 Bus 的 register(Object object) 方法在MainActivity的执行过程:

public class Bus{.......省略.......public void register(Object object) {if (object == null) {throw new NullPointerException("Object to register must not be null.");}// 检查线程,如果不是对应的线程则抛异常;默认的构造方法里使用的是主线程;// enforcer 就是构造过程中注入的默认参数 ThreadEnforcer.MAIN;// 它是 ThreadEnforcer 的一个实例,实现的 enforce(Bus bus)方法里会进行线程检查enforcer.enforce(this);  // 1// handlerFinder 就是构造过程中注入的默认参数 HandlerFinder.ANNOTATED;// 它是 HandlerFinder 的一个实例,实现了两个方法:findAllProducers(Object listener) 和 findAllSubscribers(Object listener);// findAllProducers(Object listener) 内部调用了 AnnotatedHandlerFinder 的 findAllProducers(Object listener);// 因为 MainActivity 中并没有 @Produce 的注解方法,所以这里返回的map大小是0,相关的逻辑也不再执行,接下来程序就会执行 handlerFinder.findAllSubscribers(object)方法;Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object); // 2.......省略.......// handlerFinder 就是构造过程中注入的默认参数 HandlerFinder.ANNOTATED;// findAllSubscribers(Object listener) 内部调用了 AnnotatedHandlerFinder 的 findAllSubscribers(Object listener);// 这里返回的map是;Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);  // 3for (Class<?> type : foundHandlersMap.keySet()) {Set<EventHandler> handlers = handlersByType.get(type);if (handlers == null) {//concurrent put if absentSet<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();handlers = handlersByType.putIfAbsent(type, handlersCreation);if (handlers == null) {handlers = handlersCreation;}}final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);if (!handlers.addAll(foundHandlers)) {throw new IllegalArgumentException("Object already registered.");}}for (Map.Entry<Class<?>, Set<EventHandler>> entry : foundHandlersMap.entrySet()) {Class<?> type = entry.getKey();EventProducer producer = producersByType.get(type);if (producer != null && producer.isValid()) {Set<EventHandler> foundHandlers = entry.getValue();for (EventHandler foundHandler : foundHandlers) {if (!producer.isValid()) {break;}if (foundHandler.isValid()) {dispatchProducerResultToHandler(foundHandler, producer);}}}}}.......省略.......}

标注1处,即ThreadEnforcer类的处理逻辑:

public interface ThreadEnforcer {void enforce(Bus bus);ThreadEnforcer ANY = new ThreadEnforcer() {@Override public void enforce(Bus bus) {// Allow any thread.}};ThreadEnforcer MAIN = new ThreadEnforcer() {@Override public void enforce(Bus bus) {if (Looper.myLooper() != Looper.getMainLooper()) {throw new IllegalStateException("Event bus " + bus + " accessed from non-main thread " + Looper.myLooper());}}};}

HandlerFinder类的具体处理逻辑:

interface HandlerFinder {Map<Class<?>, EventProducer> findAllProducers(Object listener);Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener);HandlerFinder ANNOTATED = new HandlerFinder() {@Overridepublic Map<Class<?>, EventProducer> findAllProducers(Object listener) {return AnnotatedHandlerFinder.findAllProducers(listener);}@Overridepublic Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {return AnnotatedHandlerFinder.findAllSubscribers(listener);}};
}

标注2处具体调用的方法:

final class AnnotatedHandlerFinder {/** Cache event bus producer methods for each class. */private static final ConcurrentMap<Class<?>, Map<Class<?>, Method>> PRODUCERS_CACHE =new ConcurrentHashMap<Class<?>, Map<Class<?>, Method>>();/** Cache event bus subscriber methods for each class. */private static final ConcurrentMap<Class<?>, Map<Class<?>, Set<Method>>> SUBSCRIBERS_CACHE =new ConcurrentHashMap<Class<?>, Map<Class<?>, Set<Method>>>();.......省略........../** This implementation finds all methods marked with a {@link Produce} annotation. */static Map<Class<?>, EventProducer> findAllProducers(Object listener) { // listener 就是示例代码中的 MainActivity 的实例对象// final Class<?> listenerClass = listener.getClass();Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();// 此时缓存中还没有,methods集合为null;Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);if (null == methods) {methods = new HashMap<Class<?>, Method>();loadAnnotatedProducerMethods(listenerClass, methods);}// 因为当前MainActivity里只有Subject注解的方法,所在这个集合大小是0;if (!methods.isEmpty()) {for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {EventProducer producer = new EventProducer(listener, e.getValue());handlersInMethod.put(e.getKey(), producer);}}// 当前这个返回结果集合大小是0;return handlersInMethod;}.......省略..........}

 loadAnnotatedProducerMethods(Class<?> listenerClass, Map<Class<?>, Method> producerMethods) 方法,最终调用loadAnnotatedMethods(Class<?> listenerClass,
      Map<Class<?>, Method> producerMethods, Map<Class<?>, Set<Method>> subscriberMethods) 这个方法

.......省略.........private static void loadAnnotatedProducerMethods(Class<?> listenerClass,Map<Class<?>, Method> producerMethods) {Map<Class<?>, Set<Method>> subscriberMethods = new HashMap<Class<?>, Set<Method>>();loadAnnotatedMethods(listenerClass, producerMethods, subscriberMethods);}/*** Load all methods annotated with {@link Produce} or {@link Subscribe} into their respective caches for the* specified class.*/private static void loadAnnotatedMethods(Class<?> listenerClass,Map<Class<?>, Method> producerMethods, Map<Class<?>, Set<Method>> subscriberMethods) { // 传入的参数: 图1for (Method method : listenerClass.getDeclaredMethods()) {// The compiler sometimes creates synthetic bridge methods as part of the// type erasure process. As of JDK8 these methods now include the same// annotations as the original declarations. They should be ignored for// subscribe/produce.// 如果桥接方法,则不处理if (method.isBridge()) {continue;}// 判断方法是否以@Subscribe为注解if (method.isAnnotationPresent(Subscribe.class)) {Class<?>[] parameterTypes = method.getParameterTypes();// 方法的参数类型的数量只能有1个,否则抛出异常if (parameterTypes.length != 1) {throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation but requires "+ parameterTypes.length + " arguments.  Methods must require a single argument.");}Class<?> eventType = parameterTypes[0];if (eventType.isInterface()) {throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType+ " which is an interface.  Subscription must be on a concrete class type.");}// 方法的访问修饰符必须是public;if ((method.getModifiers() & Modifier.PUBLIC) == 0) {throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType+ " but is not 'public'.");}Set<Method> methods = subscriberMethods.get(eventType);if (methods == null) {methods = new HashSet<Method>();subscriberMethods.put(eventType, methods);}methods.add(method);// 判断方法是否以@Produce为注解} else if (method.isAnnotationPresent(Produce.class)) {Class<?>[] parameterTypes = method.getParameterTypes();if (parameterTypes.length != 0) {throw new IllegalArgumentException("Method " + method + "has @Produce annotation but requires "+ parameterTypes.length + " arguments.  Methods must require zero arguments.");}// 方法的必须要有返回参数;if (method.getReturnType() == Void.class) {throw new IllegalArgumentException("Method " + method+ " has a return type of void.  Must declare a non-void type.");}Class<?> eventType = method.getReturnType();if (eventType.isInterface()) {throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType+ " which is an interface.  Producers must return a concrete class type.");}if (eventType.equals(Void.TYPE)) {throw new IllegalArgumentException("Method " + method + " has @Produce annotation but has no return type.");}// 方法的访问修饰符必须是public;if ((method.getModifiers() & Modifier.PUBLIC) == 0) {throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType+ " but is not 'public'.");}if (producerMethods.containsKey(eventType)) {throw new IllegalArgumentException("Producer for type " + eventType + " has already been registered.");}producerMethods.put(eventType, method);}}PRODUCERS_CACHE.put(listenerClass, producerMethods);SUBSCRIBERS_CACHE.put(listenerClass, subscriberMethods);}.......省略.........

图1:

当查找到第一个以 Subscribe 为注解的 refreshMessage(EventData eventData)方法时,数据的处理流程:

1、判断参数个数

2、判断参数类型是否是接口类型

3、保存到对应的集合中

当查找到第二个以 Subscribe 为注解的 updateMessage(EventData eventData)方法时,数据的处理流程:

查找完所有以 Subscribe 为注解的方法后,再缓存入这个集合中:

总结一下上述方法中出现的集合存储的数据类型:

Map<Class<?>, Set<Method>> subscriberMethods 集合存入的数据类型:

key 是 EventData 的Class对象

value 是Set<Method>集合,比如:refreshMessage(EventData eventData)方法 和 updateMessage(EventData eventData)方法;

ConcurrentMap<Class<?>, Map<Class<?>, Set<Method>>> SUBSCRIBERS_CACHE 集合存入的数据可以是:

key 是 MainActivity 的Class对象

value 是 subscriberMethods 集合;

 标注3处最终调用的方法:

final class AnnotatedHandlerFinder {/** Cache event bus producer methods for each class. */private static final ConcurrentMap<Class<?>, Map<Class<?>, Method>> PRODUCERS_CACHE =new ConcurrentHashMap<Class<?>, Map<Class<?>, Method>>();/** Cache event bus subscriber methods for each class. */private static final ConcurrentMap<Class<?>, Map<Class<?>, Set<Method>>> SUBSCRIBERS_CACHE =new ConcurrentHashMap<Class<?>, Map<Class<?>, Set<Method>>>();.......省略........../** This implementation finds all methods marked with a {@link Subscribe} annotation. */static Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {Class<?> listenerClass = listener.getClass(); Map<Class<?>, Set<EventHandler>> handlersInMethod = new HashMap<Class<?>, Set<EventHandler>>();// 此时缓存中已经有数据,如果没有,最终还会调用上述的查找所有Subscribe注解的方法Map<Class<?>, Set<Method>> methods = SUBSCRIBERS_CACHE.get(listenerClass);if (null == methods) {methods = new HashMap<Class<?>, Set<Method>>();loadAnnotatedSubscriberMethods(listenerClass, methods);}if (!methods.isEmpty()) {// 遍历这个集合,将数据封装到EventHandler的对象中,然后存入Map<Class<?>, Set<EventHandler>>集合中for (Map.Entry<Class<?>, Set<Method>> e : methods.entrySet()) {Set<EventHandler> handlers = new HashSet<EventHandler>();for (Method m : e.getValue()) {handlers.add(new EventHandler(listener, m));}handlersInMethod.put(e.getKey(), handlers);}}return handlersInMethod;}.......省略..........}

总结一下这段代码执行完之后的数据情况:

循环遍历了集合 Map<Class<?>, Set<Method>> subscriberMethods 集合存入的数据可以是:

key 是 EventData 的Class对象

value 是Set<Method>集合,比如:refreshMessage(EventData eventData)方法 和 updateMessage(EventData eventData)方法

找到每一个key下对应的Set<Method>集合,然后遍历这个集合,将相应数据封装到 EventHandler 对象中,并且存入Set<EventHandler > 集合中,里层循环结束后,再将数据存入 Map<Class<?>, Set<EventHandler>> handlersInMethod 集合中;

EventHandler 对象创建时注入的参数 new EventHandler(listener, m);listener 是 MainActivity的Class对象,m 是 Subscribe注释方法 refreshMessage(EventData eventData)方法;

 Map<Class<?>, Set<EventHandler>> handlersInMethod 集合的 key 是 EventData 的Class对象,value 是 Set<EventHandler > 集合;

 下面我们回到Bus里标注3的返回结果:

public class Bus{.......省略.......public void register(Object object) {.......省略.......Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object); // 3for (Class<?> type : foundHandlersMap.keySet()) {// 此时handlersByType集合还是0,查找出的结果集合还是null;Set<EventHandler> handlers = handlersByType.get(type);if (handlers == null) {//concurrent put if absentSet<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();// 此时key对应的value还不存在,此方法会添加key和value,并且返回nullhandlers = handlersByType.putIfAbsent(type, handlersCreation);if (handlers == null) {// 将 CopyOnWriteArraySet类型的集合对象 handlersCreation 赋值给 handlershandlers = handlersCreation;}}final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);// 如果Set集合发生更改,则返回true。if (!handlers.addAll(foundHandlers)) {throw new IllegalArgumentException("Object already registered.");}}.......省略.......}

总结一下数据情况:

ConcurrentMap<Class<?>, Set<EventHandler>> handlersByType 的 key 是 EventData 的Class对象,value 是 Set<EventHandler > 集合;

到此注册方法的执行流程已经完成。

示例代码GitHub地址

由于作者水平有限,语言描述及代码实现中难免有纰漏,望各位看官多提宝贵意见!

Hello , World !

感谢所有!

这篇关于Android事件总线框架Otto源码解析一(Bus的构造过程及在使用注解@Subscribe时的注册过程)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/404851

相关文章

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud