EventBus基础

来源:互联网 发布:chown linux 编辑:程序博客网 时间:2024/05/29 18:38

            EventBus是Android下高效的发布/订阅事件总线机制。作用是可以代替传统的Intent,Handler,Broadcast或接口函数在Fragment,Activity,Service,线程之间传递数据,执行方法。特点是代码简洁,是一种发布订阅设计模式(Publish/Subsribe),或称作观察者设计模式。

EventBus 文档:http://greenrobot.org/eventbus/documentation/

 一,定义事件:

 定义一个事件,用于传递相应的事件信息,只要定义一个普通的Java类,无任何特殊要求。
public class SomeEvents{  private String mInfos ;  public SomeEvents(String infos){    mInfos=infos;  }}

二,注册成订阅者:

 对于Android来说,一般在Activity或Fragment的生命周期方法中进行注册,注册的同时,千万别忘了在相应的生命周期方法中反注册。

@Overridepublic void onStart() {    super.onStart();    EventBus.getDefault().register(this);}@Overridepublic void onStop() {   EventBus.getDefault().unregister(this);    super.onStop();}

三,定义注册方法:

当一个事件发生时,对这个事件感兴趣的订阅者中相应的注册方法就会被调用,所以应该定义好相应的注册方法,对相应的事件进行处理。

@Subscribe(threadMode = ThreadMode.MAIN)public void onEventArrived(SomeEvent event) {    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();}

通过@Subscribe注解定义相应的方法,其中threadMode定义的是注册方法在那个线执行,一共有四个值,分别为POSTING、MAIN、BACKGROUND、ASYNC。
    Thread.POSTING : 注册方法将会在事件被post出来的线程执行;
    Thread.MAIN: 注册方法将会在主线程(UI线程)执行;
    Thread.BACKGROUND: 如果事件被post出来的线程不是主线程,那么注册方法在此线程执行,否则在后台线程执行;
    Thread.ASYNC: 注册方法将会在一个独立的线程执行;

四,Post事件:

可以调用以下方法来post出一个事件,从而使订阅者相应的注册方法被调用。

EventBus.getDefault().post(new SomeEvents("evetnsInfos"));

五,Sticky Events:

            对于有些事件,可能后来者也会感兴趣,这样的事件被称为Sticky 事件,例如:地理位置。EventBus会维护每一个Sticky 事件的缓存,当有同类的事件来临时,缓存就会以被更新,同时如果在事件Post后有新的订阅都对Sticky 事件感兴趣,那么订阅者的相应方法(sticky =true)会立即被调用,不用再等到事件重新post。post Sticky事件时调用以下方法:
EventBus.getDefault().postStick(new SomeEvents("evetnsInfos"));
删除Sticky Events:
SomeEvents stickyEvent=EventBus.getDefault().getStickyEvent(SomeEvents.class);if(stickyEvent != null) {    EventBus.getDefault().removeStickyEvent(stickyEvent);}
或者:
EventBus.getDefault().removeStickyEvent(SomeEvents.class);

六,优先级:

           对于每个注册方法,都可以通过@Subscribe(priority = 1)来配置优先级,当然这种优先级是针对同一ThreadMode而言的。高优先级的注册方法能先接收到事件,并且可以通过调用EventBus.getDefault().cancelEventDelivery(event) 取消事件的传递。

七,源码分析:

一,首先来看EventBus.getDefault().register(Object obj)干啥了:
先看看EventBus几个重要变量的意义:
 /**     * 每个事件与他的所有订阅者的映射关系     */    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;    /**     * 订阅者与它自己的订阅方法的映射关系     */    private final Map<Object, List<Class<?>>> typesBySubscriber;    /**     * 存贮post过来的stickyEvents     */    private final Map<Class<?>, Object> stickyEvents;


1,首先是通过EventBus.getDefault()得到了一个单例对象(单例模式)
   /**     * Convenience singleton for apps using a process-wide EventBus instance.     */    public static EventBus getDefault() {        if (defaultInstance == null) {            synchronized (EventBus.class) {                if (defaultInstance == null) {                    defaultInstance = new EventBus();                }            }        }        return defaultInstance;    }

2,得到一个EventBus单例对象后调用register(Object obj)来注册订阅者的相关信息
    public void register(Object subscriber) {        Class<?> subscriberClass = subscriber.getClass();        //通过Class对象找到相应类中定义的订阅方法        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);        synchronized (this) {            for (SubscriberMethod subscriberMethod : subscriberMethods) {                //得到订阅者中的订阅方法后对方法的信息进行注册登记                subscribe(subscriber, subscriberMethod);            }        }    }
 
3,其中subscriberMethodFinder是一个工具类,正所谓名符其实。它主要的工作就是找到每个订阅者所有的订阅方法。
  List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);        //如果已经注册过了就直接返回该类下所有的方法集合        if (subscriberMethods != null) {            return subscriberMethods;        }        //ignoreGeneratedIndex 暂时是为false        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;        }    }


4,接着看findUsingInfo(Class<?> subscriberClass)
    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {        FindState findState = prepareFindState();        findState.initForSubscriber(subscriberClass);        //通过 moveToSuperclass()方法更新 findState.clazz,即得到父类class ,直到为null        //如果父类已订阅了某一事件,那么子类理所应当的也有了相应的订阅方法        //即,EventBus支持了继承        while (findState.clazz != null) {            //这个方法暂时是返回空,因为findState.subscriberInfo与subscriberInfoIndexes均为空            findState.subscriberInfo = getSubscriberInfo(findState);            if (findState.subscriberInfo != null) {                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();                for (SubscriberMethod subscriberMethod : array) {                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {                        findState.subscriberMethods.add(subscriberMethod);                    }                }            } else {                  //跳转到这,检索当前类的订阅方法                findUsingReflectionInSingleClass(findState);            }            //检索父类            findState.moveToSuperclass();        }        return getMethodsAndRelease(findState);    }


5,检索当前类的订阅方法: findUsingReflectionInSingleClass(findState);

    private void findUsingReflectionInSingleClass(FindState findState) {        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            methods = findState.clazz.getMethods();            findState.skipSuperClasses = true;        }        for (Method method : methods) {            int modifiers = method.getModifiers();            //忽略非public , abstract,static ,bridge,synthetic的方法            //compilers may add methods. Those are called bridge or synthetic methods.            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {                Class<?>[] parameterTypes = method.getParameterTypes();                //EventBus的订阅方法有且只有一个参数                if (parameterTypes.length == 1) {                    //得到相应的注解                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);                    if (subscribeAnnotation != null) {                        Class<?> eventType = parameterTypes[0];                        // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.                        // Usually a subscriber doesn't have methods listening to the same event type.                        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)) {                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();                    throw new EventBusException("@Subscribe method " + methodName +                            "must have exactly 1 parameter but has " + parameterTypes.length);                }            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {                String methodName = method.getDeclaringClass().getName() + "." + method.getName();                throw new EventBusException(methodName +                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");            }        }    }





0 0