EventBus基础

            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的生命周期方法中进行注册,注册的同时,千万别忘了在相应的生命周期方法中反注册。

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值