事件总线源码解析

xiaoxiao2021-02-28  103

事件总线

基本上都是观察者模式的扩展

Google/Guava:Guava是一个庞大的库,EventBus只是它附带的一个小功能,因此实际项目中使用并不多

greenrobot/EventBus:简洁体量小

square/otto:修改自 Guava,官方已经标记为过时了,并推荐使用RxJava代替它。

RxJava:主要用于响应式编程。

使用

EventBus

1、注册和注销:

@Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public 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、处理事件:

@Subscribe public 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配合。

转载请注明原文地址: https://www.6miu.com/read-64007.html

最新回复(0)