事件总线源码解析
来源:互联网 发布:网络情感电台结束语 编辑:程序博客网 时间:2024/06/14 18:30
事件总线
基本上都是观察者模式的扩展
Google/Guava:Guava是一个庞大的库,EventBus只是它附带的一个小功能,因此实际项目中使用并不多
greenrobot/EventBus:简洁体量小
square/otto:修改自 Guava,官方已经标记为过时了,并推荐使用RxJava代替它。
RxJava:主要用于响应式编程。
使用
EventBus
1、注册和注销:
@Overridepublic void onStart() { super.onStart(); EventBus.getDefault().register(this);}@Overridepublic void onStop() { super.onStop(); EventBus.getDefault().unregister(this);}
这里请注意,activity以及fragment的生命周期,如果不了解,可以再深度学习一下。
2、定义事件,也就是实体类:
public class MessageEvent {String message;public MessageEvent(String message) { this.message = message;}public String getMessage() { return message;}public void setMessage(String message) { this.message = message;}}
3、发布事件:
EventBus.getDefault().post(new MessageEvent(message));
4、处理事件:
@Subscribepublic void onMessageEvent(MessageEvent event) { Toast.makeText(this, "收到消息", Toast.LENGTH_SHORT).show(); Log.i("111","来自PostActivity消息"+event.getMessage()); tx.setText(event.getMessage());}
这是官网的大致流程。注意:如果要把一个Event发送到一个还没有初始化的Activity/Fragment,即尚未订阅事件(也就是说在post之前,如果该Activity/Fragment还没有被初始化过,请使用postSticky())。那么请使用postSticky()方法,并将@Subscribe改为@Subscribe(sticky = true)。
EventBus
EvenBus的使用较为简单,但是很实用。一般查看源码有一个比较实用的方法:追踪使用方法,进而将整个框架的流程弄清楚,源码自然而然就清楚了。
1、这里注册为第一步:EventBus.getDefault().register(this),EventBus采用的是单例设计模式,通过getDefault()取得当前实例,register中的方法如下:
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); //核心方法1 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { //核心方法2 subscribe(subscriber, subscriberMethod); } }}
可以看到首先通过反射得到了订阅类的类型,接下来是组装了一个List,这里看一下SubscriberMethod是什么:
public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) { this.method = method; this.threadMode = threadMode; this.eventType = eventType; this.priority = priority; this.sticky = sticky;}
哦,一看,原来是订阅信息的实体包装类。回到主方法,首先追踪核心方法1,findSubscriberMethods(subscriberClass)方法,追踪进去:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { //这里首先从缓存中获取 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } //是否忽略注解器生成的MyEventBusIndex类 if (ignoreGeneratedIndex) { //使用注解 subscriberMethods = findUsingReflection(subscriberClass); } else { //使用注解器 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<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass();//将subscriberClass向上转型为父类,比如某一个DemoActivity.class,转为Activity.class } return getMethodsAndRelease(findState);//重新组装}
这里有一个FindState内部类,看其构造器以及类属性:
final List<SubscriberMethod> subscriberMethods = new ArrayList<>(); final Map<Class, Object> anyMethodByEventType = new HashMap<>(); final Map<String, Class> subscriberClassByMethodKey = new HashMap<>(); final StringBuilder methodKeyBuilder = new StringBuilder(128); Class<?> subscriberClass; Class<?> clazz; boolean skipSuperClasses; SubscriberInfo subscriberInfo; void initForSubscriber(Class<?> subscriberClass) { this.subscriberClass = clazz = subscriberClass; skipSuperClasses = false; subscriberInfo = null; }
主要存储的是方法是一系列订阅方法。追踪findUsingReflectionInSingleClass(findState):
private void findUsingReflectionInSingleClass(FindState findState) { //定义一个Method数组 Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 //取得类中的所有的方法,比如在Activity中,onCreate,onStart方法都会取到 methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } 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) { //取得注解 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { //取得参数 Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { //关键是下面两行,对方法进行组装。 ThreadMode threadMode = subscribeAnnotation.threadMode(); findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { //省略 } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { //省略 } }}
回到getMethodsAndRelease(findState)方法;
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { if (FIND_STATE_POOL[i] == null) { FIND_STATE_POOL[i] = findState; break; } } } return subscriberMethods;}
构造了一个List,同时释放findState资源,并返回List。至此已经取得了所有所有被@Subscribe注解标记的方法信息。
接下来是执行核心方法2:
主要作用是将SubscriberMethod填充到两个Map中,
//订阅者和订阅方法一一对应的组合成一个Subscription类
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
//key:订阅EventType,也就是传递和接收时的实体信息类EventType比如MessageEvent; values:所有订阅了该类型的Subscription集合。主要用于在post中执行时取出private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;//key订阅者;values订阅EventType集合,主要用于判断是否注册成功以及注销private final Map<Object, List<Class<?>>> typesBySubscriber;
同时定义了Sticky策略的处理方法–二次调用:
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
通俗的来说订阅者就是任意一个注册了的Activity/Fragment,这里就可以看出单例模式设计的威力。
2、到这里注册已经基本完成了,接下来是事件发送
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; } }}
追踪postSingleEvent来到:postSingleEventForEventType,核心代码如下:
//通过EventType取得一个Subscription的List subscriptions = subscriptionsByEventType.get(eventClass); //省略了循环List取得subscription postToSubscription(subscription, event, postingState.isMainThread);
然后来到下一步:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { //默认模式 case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; case ASYNC: asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); }}
最终的执行如下,使用反射执行方法:
void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); }}
到此为止,基本流程已经走通,还有一个Sticky策略,也是类似,postSticky()方法只是异步维护了一个stickyEvents,最终还是要调用post方法,只是此时register还没有初始化,所以订阅者和订阅方法都为空。
RXJava:
基本上是跟Retrofit配合。
- 事件总线源码解析
- Android 事件总线OTTO使用说明和源码解析
- Android事件总线(二)EventBus3.0源码解析
- Android事件总线(四)源码解析otto
- Android事件总线(四)源码解析otto
- Android事件总线(二)EventBus3.0源码解析
- 【事件总线】解析EventBus
- android事件总线EventBus解析
- EventBus --事件总线原理解析
- QT 事件机制 源码解析
- 事件分发源码解析 2
- android_事件分发源码解析
- Spring 源码解析 ---- 事件监听
- 事件分发的源码解析
- ViewGropw 事件分发源码解析
- View的事件源码解析
- Andorid事件分发源码解析
- Android事件总线(一)EventBus3.0用法全解析
- Unity3D应用嵌入WPF应用并实现通信
- 创建和使用临时表
- Python编程:从入门到实践读书笔记-8 函数
- 第40章 连续时间系统的模拟
- 用tomcat作为服务器配置finereport报表平台
- 事件总线源码解析
- 选择结构语句---if语句,switch语句
- mybatis批量更新update的各种情况总结
- 【TopDesk】3.1.2. 利用JNI在Java中检测耳机插拔
- (第二行代码阅读笔记)活动(Activity)的生命周期
- UIView.h解读
- 数字在排序数组中出现的次数
- 设计模式—抽象工厂(十一)
- #5 计算属性与数据集合