事件总线源码解析

来源:互联网 发布:网络情感电台结束语 编辑:程序博客网 时间: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配合。