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
- EventBus基础
- EventBus使用之基础
- EventBus使用之基础
- android EventBus基础介绍
- EventBus---基础讲解
- EventBus 3.0 (一) 基础
- EventBus 3.0使用基础
- EventBus 基础篇
- EventBus使用之基础
- EventBus使用基础
- EventBus之基础使用详解
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- 多线程编程 - NSOperationQueue
- 小总结:字符串和数字的简单相互转换
- Textarea判空
- 【刷题之路】树的子结构
- SVN使用
- EventBus基础
- UVA - 10161 Ant on a Chessboard
- git将单个文件恢复到历史版本的方法
- UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)
- 程序员表白程序
- Python 决策树
- Mirantis OpenStack Fuel9.0离线安装(MOS9.0本地源)
- 使用eclipse调试openfre3.9.3源码
- base64