EventBus高级使用姿势
2016-08-10 14:26
176 查看
如果你还没用过EventBus,强烈建议你看这篇文章点这里
打印订阅者异常信息
打印没有订阅者的消息
订阅者处理事件出现异常发送异常信息
发送没有订阅者的消息
。。。
基于此,我们需要能自主控制EventBus的一些行为,这时就需要定制适合业务的EventBus
在正式介绍如何定制EventBus之前先介绍一下定制的两种方式
* 使用EventBus.builder()生成一个EventBusBuilder,使用这个EventBusBuilder构造定制的EventBus,然后在所有使用到EventBus的地方使用这个定制的EventBus,这种方式可以定制多种不同行为的EventBus以供使用
* 定制默认的EventBus,使用EventBus.builder().installDefaultEventBus()方法定制默认的EventBus,这种方式定制完成之后使用EventBus.getDefault()方法获得EventBus
以上两种方法各有优劣,各位看官根据业务进行取舍
不管是使用上面两种方法的哪一种,都离不开一个类EventBusBuilder,查看源码可以发现,在EventBusBuilder中右几个默认的属性
如果没有定制默认的EventBus,上面的属性就为默认属性,这些属性会决定EventBus的行为,具体属性控制的行为我们将在以后的源码分析中解释,鉴于此,各位现在知道如何定制EventBus的行为就可以了
举个最常见的例子:一个具有定位功能的APP,定位逻辑在Service中,有Service决定什么时候可以发送位置信息,当我们进入一个Activity中时,需要立即获取一个最新的地址信息,但是这个时候Service已经发送完位置信息了,如果我们在Activity中等待位置信息,显然是不友好的,这时就需要使用Sticky Events。
首先介绍一下使用方法
编写处理事件方法
注册EventBus
有人可能会有疑问,为什么要把注册EventBus放在最后呢,原因是一旦注册了EventBus,置顶事件就会发送到事件处理函数中,具体原理会在后面的源码分析中说明
还有另一种方式获取置顶事件,那就是直接调用方法获取,
这种方式简单粗暴,不需要注册EventBus,也不需要编写事件处理函数,但是只能显式调用,后面如果还有相同的事件发送出来就不能及时获取到,也就不能及时处理,所以还是需要按需取舍
既然能直接获取到消息,那就应该能移除消息,没错,看下面代码
上面介绍了两种移除消息的方法,还是按需取舍
注意一下:优先级只是在相同的ThreadMode中才有效,不同的ThreadMode不起作用
首先介绍一下如何使用优先级,上代码:
然后如何取消后续的事件传递呢
分析中会介绍到这个属性为true时会使用反射方法获取订阅者的事件处理函数,为false时会使用subscriber Index生成的SubscriberInfo来获取订阅者的事件处理函数,具体内容会在源码分析中介绍
首先,Subscriber Index会在编译期间生成SubscriberInfo,然后在运行时使用SubscriberInfo中保存的事件处理函数处理事件,减少了反射时需要是耗时,会有运行速度上的提升,但是用起来会比较麻烦。。。。
注意,添加注解处理器的时候还需要添加参数:生成索引的名字
2. 修改完Gradle之后build项目,如果没有错误会自动生成 “eventBusIndex” 文件,这个时候就可以初始化EventBus,上面讲过,自定义EventBus的两种方式,如下代码:
不用多说相信你也能明白,顺便说一句,MyEventBusIndex的路径为:项目根目录\build\generated\source\apt\debug\包名\MyEventBusIndex.java
3.如果有多个索引文件还可以使用下面的代码:
只要有代码混淆,就需要上述代码!
配置适合业务的EventBus
EventBus中有一个获取默认实例的方法EventBus.getDefault(),默认的EventBus有以下几个特点(包括但不限于)打印订阅者异常信息
打印没有订阅者的消息
订阅者处理事件出现异常发送异常信息
发送没有订阅者的消息
。。。
基于此,我们需要能自主控制EventBus的一些行为,这时就需要定制适合业务的EventBus
在正式介绍如何定制EventBus之前先介绍一下定制的两种方式
* 使用EventBus.builder()生成一个EventBusBuilder,使用这个EventBusBuilder构造定制的EventBus,然后在所有使用到EventBus的地方使用这个定制的EventBus,这种方式可以定制多种不同行为的EventBus以供使用
* 定制默认的EventBus,使用EventBus.builder().installDefaultEventBus()方法定制默认的EventBus,这种方式定制完成之后使用EventBus.getDefault()方法获得EventBus
以上两种方法各有优劣,各位看官根据业务进行取舍
不管是使用上面两种方法的哪一种,都离不开一个类EventBusBuilder,查看源码可以发现,在EventBusBuilder中右几个默认的属性
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); boolean logSubscriberExceptions = true; boolean logNoSubscriberMessages = true; boolean sendSubscriberExceptionEvent = true; boolean sendNoSubscriberEvent = true; boolean throwSubscriberException;//没有赋值的为false boolean eventInheritance = true; boolean ignoreGeneratedIndex; boolean strictMethodVerification; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List<Class<?>> skipMethodVerificationForClasses;//没有赋值的为null List<SubscriberInfoIndex> subscriberInfoIndexes;
如果没有定制默认的EventBus,上面的属性就为默认属性,这些属性会决定EventBus的行为,具体属性控制的行为我们将在以后的源码分析中解释,鉴于此,各位现在知道如何定制EventBus的行为就可以了
Sticky Events(置顶事件)
所谓置顶事件,顾名思义就是后来的消息在先来的消息之上,也就是栈的结构;但是在EventBus中,不是栈的结构,而是后来的消息会把先来的消息覆盖掉,保证消息的最新,不关心以前的消息内容,具体实现会在后面的源码分析中说明。举个最常见的例子:一个具有定位功能的APP,定位逻辑在Service中,有Service决定什么时候可以发送位置信息,当我们进入一个Activity中时,需要立即获取一个最新的地址信息,但是这个时候Service已经发送完位置信息了,如果我们在Activity中等待位置信息,显然是不友好的,这时就需要使用Sticky Events。
首先介绍一下使用方法
EventBus.getDefault().postSticky(new MessageEvent("111","222"));//使用EventBus.postSticky()方法发送置顶事件
编写处理事件方法
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)//注意此处需要增加sticky = true,表明处理置顶事件 public void handleEvent(MessageEvent event) { // UI updates must run on MainThread textView.setText(event.message); }
注册EventBus
EventBus.getDefault().register(this);
有人可能会有疑问,为什么要把注册EventBus放在最后呢,原因是一旦注册了EventBus,置顶事件就会发送到事件处理函数中,具体原理会在后面的源码分析中说明
还有另一种方式获取置顶事件,那就是直接调用方法获取,
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class); // Better check that an event was actually posted before if(stickyEvent != null) { // "Consume" the sticky event }
这种方式简单粗暴,不需要注册EventBus,也不需要编写事件处理函数,但是只能显式调用,后面如果还有相同的事件发送出来就不能及时获取到,也就不能及时处理,所以还是需要按需取舍
既然能直接获取到消息,那就应该能移除消息,没错,看下面代码
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);//根据消息的类型移除消息,返回最后的消息内容 boolean b = EventBus.getDefault().removeStickyEvent(event);//根据具体消息进行移除操作,返回移除结果,成功或者失败
上面介绍了两种移除消息的方法,还是按需取舍
观察者的优先级
在EventBus中,观察者也就是Subscription的优先级默认都为0,级别越高,越早收到消息,并且收到消息之后还能阻断后面观察者接收消息,颇有点像有序广播。注意一下:优先级只是在相同的ThreadMode中才有效,不同的ThreadMode不起作用
首先介绍一下如何使用优先级,上代码:
@Subscribe(priority = 1)//设置优先级为1 public void onEvent(MessageEvent event) { //do something }
然后如何取消后续的事件传递呢
@Subscribe public void onEvent(MessageEvent event){ // Process the event … EventBus.getDefault().cancelEventDelivery(event) ;//取消事件传递,事件到此为止 }
EventBus 3.X新特性Subscriber Index
简介
注意最开始我们介绍了一些默认属性,在默认属性中有一个属性为ignoreGeneratedIndex,在后面的源码分析中会介绍到这个属性为true时会使用反射方法获取订阅者的事件处理函数,为false时会使用subscriber Index生成的SubscriberInfo来获取订阅者的事件处理函数,具体内容会在源码分析中介绍
首先,Subscriber Index会在编译期间生成SubscriberInfo,然后在运行时使用SubscriberInfo中保存的事件处理函数处理事件,减少了反射时需要是耗时,会有运行速度上的提升,但是用起来会比较麻烦。。。。
如何使用新特性Subscriber Index
注意事项
只有用注解@Subscriber描述的public方法才能被索引,并且由于Java的特性匿名内部类就算用@Subscriber描述也不能被索引,不过别担心,当EventBus不能使用索引时会自动在运行时使用反射方法获取事件处理函数使用步骤
要添加事件处理函数到索引需要借助EventBus的注解处理器,添加EventBus的注解处理器到Module的Gradle文件中:buildscript { dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } apply plugin: 'com.neenbedankt.android-apt' dependencies { compile 'org.greenrobot:eventbus:3.0.0' apt 'org.greenrobot:eventbus-annotation-processor:3.0.1' } apt { arguments { eventBusIndex "包名.MyEventBusIndex"//生成索引的名称 } }
注意,添加注解处理器的时候还需要添加参数:生成索引的名字
2. 修改完Gradle之后build项目,如果没有错误会自动生成 “eventBusIndex” 文件,这个时候就可以初始化EventBus,上面讲过,自定义EventBus的两种方式,如下代码:
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus(); // Now the default instance uses the given index. Use it like this: EventBus eventBus = EventBus.getDefault();
不用多说相信你也能明白,顺便说一句,MyEventBusIndex的路径为:项目根目录\build\generated\source\apt\debug\包名\MyEventBusIndex.java
3.如果有多个索引文件还可以使用下面的代码:
EventBus eventBus = EventBus.builder() .addIndex(new MyEventBusAppIndex()) .addIndex(new MyEventBusLibIndex()).build();
如果项目中使用了代码混淆,这一节一定要看!!!
EventBus的事件处理函数在IDE看来是没有被调用的,所以在代码混淆阶段就会被删除!所以必须告诉ProGuard不能删除事件处理函数,上代码:-keepattributes *Annotation*//有注解的不参与混淆 -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } # Only required if you use AsyncExecutor -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { <init>(java.lang.Throwable); }
只要有代码混淆,就需要上述代码!
相关文章推荐
- Android神器:高效事件通信总线EventBus,简例讲解,进阶中高级工程师必看!(附带碎片Fragment高级使用技巧)
- Linux高级使用技巧十五课(二)
- 高级浏览功能可以使用了
- 使用 ADO.NET 和 Oracle 进行高级数据访问
- .net中的正则表达式使用高级技巧 (四)
- .net中的正则表达式使用高级技巧 (一)(from thinhunan's blog)
- .net中的正则表达式使用高级技巧 (一)
- 使用 ADO.NET 和 Oracle 进行高级数据访问
- .net中的正则表达式使用高级技巧
- .net中的正则表达式使用高级技巧 (三)
- [翻译] 第四章,高级串口编程 - 使用 ioctl 和 select
- 使用 ADO.NET 和 Oracle 进行高级数据访问
- 续:ibatis使用高级篇,多表操作处理!
- 使用委托进行高级ASP.NET缓存处理
- 使用J2ME高级用户界面技术开发的猜数字游戏(包含源代码)
- 在C#中使用MSHTML的高级支持接口(引自http://www.vckbase.com/document/viewdoc.asp?id=1018)
- 使用dbms_rectifier_diff解决高级复制中的数据冲突问题
- 【原理】高级缓冲溢出的使用
- 高级对弈程序如Crafty(使用C语言编写)使用了特殊的数据结构
- J2ME中文教程 3 MIDP高级UI 的使用