事件总线源码解析

事件总线

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

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配合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值