EventBus3.0注意事项

1、父类中定义的订阅方法不能被重写

比如你在父类中定义了一个订阅方法 

@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(Item item) {
}

那么不能在子类中重写该方法,否则一旦我们调用EventBus.getDefault().regist(this)后,EventBus就会查询当前类及其父类中的订阅方法,如果发现父类中也订阅了相同的订阅方法(被子类override了),则会抛出异常,源码参见:

SubscriberMethodFinder.FindState类中的checkAdd();

boolean checkAdd(Method method, Class<?> eventType) {
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
    return true;
} else {
    if (existing instanceof Method) {
    //检测被子类override的方法并抛出异常,如果子类覆写了父类中的订阅方法,则在查找父类中的同名方法时,会抛出异常。
        if (!checkAddWithMethodSignature((Method) existing, eventType)) {
            throw new IllegalStateException();
        }
        anyMethodByEventType.put(eventType, this);
    }
    return checkAddWithMethodSignature(method, eventType);
}
}

2、订阅方法的要求

1)修饰符必须为pubic, 非static,非abstract

2)方法参数必须只能有一个,不能没有或有多个参数

原因参见SubscriberMethodFinder类中的findUsingReflectionInSingleClass方法

private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//获取当前类中的所有方法
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(); //得到方法的修饰符
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) { //带有Subscribe注解
//其他代码省略
}
} 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)) {
//不合法的注解方法 (必须为public,非static、非abstract)
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}


3、关于订阅事件

什么是订阅事件,其实就是订阅方法的参数

EventBus用于订阅和发送事件,在EventBus类中,定义了一个HashMap,用于保存事件及其订阅方法:

//key为订阅事件Clas,value为该事件的订阅者,可能有多个
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;

发送事件的时候,拿到该订阅事件的所有订阅方法,依次发送

 

Class<?> eventClass;//订阅事件
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//拿到订阅该事件的所有方法
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
//依次反射调用订阅方法
}
}

事件本身是个Java对象,那么就可以发生继承和接口的实现,比如我们定义了

 

public interface EventInterface{
}
public class FatherEvent implements EventInterface{
}
public class ChildEvent extends FatherEvent{
}

ChildEvent继承FatherEvent,FatherEvent实现了EventInterface接口。

 


默认情况下,EventBus是支持事件继承的订阅的,怎么理解呢。

 

比如我们订阅了如下三个方法:

@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventFather(FatherEvent fatherEvent){
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventChild(ChildEvent childEvent){
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventInterface(EventInterface eventInterface){
}

a)当我们调用 EventBus.getDefault().post(new ChildEvent()); 事件时,上面三个方法都可以监听到。

因为ChildEvent继承FatherEvent,FatherEvent又实现了EventInterface接口。

b)当我们调用 EventBus.getDefault().post(new FatherEvent()); 事件时,则订阅了FatherEvent和EventInterface接口的方法可以监听到。

因为FatherEvent实现了EventInterface。

也就是说,发送的事件时,如果该事件的父类或实现的接口被订阅,则也可以监听到。

4、事件过滤

EventBus是基于事件的,也就是订阅方法参数,用户要关心不同的事件,就需要定义不同的事件对象。

(与BrocastReceiver相比,EventBus中的事件就相当于BrocastReceiver中的action)

比如我们需要监听用户模块的登录和退出操作,就需要定义两个Event:LoginEvent和LoginOutEvent

然而实际项目中,可能我们需要监听很多的事件,就需要定义很多的事件类(然而大部分事件都只是为了区分,并没有业务实现),很多网友就想按照BrocastReceiver的方式去监听指定动作的事件(只有一个Intent,用action来区分事件),从而减少事件类的定义。

这虽然违背了观察者模式的意图,但是冗余事件类的定义,我个人也不是太喜欢,有网友提出在事件类中定义一个action来区分,根据action来区分。比如

@Subscribe(threadMode = ThreadMode.MAIN)
public void onLoginEvent(UserEvent event) {
String action = event.getAction();
if(action.equals("login")){
//监听到登录操作
}else if(action.equals("loginout")){
//监听到退出操作操作
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onInfoChangeEvent(UserEvent event) {
String action = event.getAction();
if(action.equals("infoChange")){
//监听到用户资料修改操作
}
}

这种方式实现,这样可以减少部分Event的定义,但是需要我们在方法中自己匹配action。如果能像BrocastReceiver那样注册自己想要的动作就方便很多。本人针对这种情况

做了个简单处理,已把代码方法gitbub上,链接 https://github.com/zhangquanit/EventBus-demo

大致使用流程就是,在注解Subscribe注解中添加了一个action的数组,用于指定监听动作

@Subscribe
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
boolean sticky() default false;
int priority() default 0;
/**
* 监听动作,很多网友多有这样的需求,可以想广播那样监听指定动作的事件
* @note: 设置了actions,事件必须为PostEvent及其子类,当发送事件时,会拿到PostEvent中的action进行匹配
* @return
*/
String[] actions() default {};
}

注册事件

//监听多个动作
@Subscribe(threadMode = ThreadMode.MAIN,actions = {EventAction.ACTION,EventAction.ACTION2})
public void onEventAction(PostEvent item) {
}
//监听1个动作
@Subscribe(threadMode = ThreadMode.ASYNC,actions = {EventAction.ACTION2})
public void onEventAction2(PostEvent item) {
}

发送事件,注意事件必须为PostEvent及其子类。

 

EventBus.getDefault().post(new PostEvent(EventAction.ACTION));

5、其他问题

1)混淆

-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);
}

链接:http://greenrobot.org/eventbus/documentation/proguard/

2)不支持跨进程

目前EventBus只支持跨线程,而不支持跨进程。如果一个app的service起到了另一个进程中,那么注册监听的模块则会收不到另一个进程的EventBus发出的事件。

3)为了防止多次注册,可以在注册前,先判断一下:

if (!EventBus.getDefault().isRegistered(this)) {
    EventBus.getDefault().register(this);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
方案是为解决特定问题或达成特定目标而制定的一系列计划或步骤。它的作用是提供一种系统性的方法,以有效地应对挑战、优化流程或实现目标。以下是方案的主要作用: 问题解决: 方案的核心目标是解决问题。通过系统性的规划和执行,方案能够分析问题的根本原因,提供可行的解决方案,并引导实施过程,确保问题得到合理解决。 目标达成: 方案通常与明确的目标相关联,它提供了一种达成这些目标的计划。无论是企业战略、项目管理还是个人发展,方案的制定都有助于明确目标并提供达成目标的路径。 资源优化: 方案在设计时考虑了可用资源,以最大化其效用。通过明智的资源分配,方案可以在有限的资源条件下实现最大的效益,提高效率并减少浪费。 风险管理: 方案通常会对潜在的风险进行评估,并制定相应的风险管理策略。这有助于减轻潜在问题的影响,提高方案的可行性和可持续性。 决策支持: 方案提供了决策者所需的信息和数据,以便做出明智的决策。这种数据驱动的方法有助于减少不确定性,提高决策的准确性。 团队协作: 复杂的问题通常需要多个人的协同努力。方案提供了一个共同的框架,帮助团队成员理解各自的职责和任务,促进协作并确保整个团队朝着共同的目标努力。 监控与评估: 方案通常包括监控和评估的机制,以确保实施的有效性。通过定期的评估,可以及时调整方案,以适应变化的环境或新的挑战。 总体而言,方案的作用在于提供一种有序、有计划的方法,以解决问题、实现目标,并在实施过程中最大化资源利用和风险管理。 方案是为解决特定问题或达成特定目标而制定的一系列计划或步骤。它的作用是提供一种系统性的方法,以有效地应对挑战、优化流程或实现目标。以下是方案的主要作用: 问题解决: 方案的核心目标是解决问题。通过系统性的规划和执行,方案能够分析问题的根本原因,提供可行的解决方案,并引导实施过程,确保问题得到合理解决。 目标达成: 方案通常与明确的目标相关联,它提供了一种达成这些目标的计划。无论是企业战略、项目管理还是个人发展,方案的制定都有助于明确目标并提供达成目标的路径。 资源优化: 方案在设计时考虑了可用资源,以最大化其效用。通过明智的资源分配,方案可以在有限的资源条件下实现最大的效益,提高效率并减少浪费。 风险管理: 方案通常会对潜在的风险进行评估,并制定相应的风险管理策略。这有助于减轻潜在问题的影响,提高方案的可行性和可持续性。 决策支持: 方案提供了决策者所需的信息和数据,以便做出明智的决策。这种数据驱动的方法有助于减少不确定性,提高决策的准确性。 团队协作: 复杂的问题通常需要多个人的协同努力。方案提供了一个共同的框架,帮助团队成员理解各自的职责和任务,促进协作并确保整个团队朝着共同的目标努力。 监控与评估: 方案通常包括监控和评估的机制,以确保实施的有效性。通过定期的评估,可以及时调整方案,以适应变化的环境或新的挑战。 总体而言,方案的作用在于提供一种有序、有计划的方法,以解决问题、实现目标,并在实施过程中最大化资源利用和风险管理。
EventBus是一种用于Android应用程序中发布/订阅事件的库。它遵循发布-订阅模式,允许不同组件之间进行松散耦合的通信。 在基于EventBus 3.0的APP开发中,你可以按照以下步骤进行: 1. 添加EventBus依赖 在项目的build.gradle文件中添加以下代码: ``` dependencies { implementation 'org.greenrobot:eventbus:3.2.0' } ``` 2. 创建事件类 创建一个事件类,它将包含你需要发送和接收的数据。例如: ``` public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } } ``` 3. 注册订阅者 在需要接收事件的组件中,注册订阅者。例如,在Activity中: ``` @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { EventBus.getDefault().unregister(this); super.onStop(); } ``` 4. 发布事件 在需要发送事件的组件中,发布事件。例如,在Activity中: ``` EventBus.getDefault().post(new MessageEvent("Hello, world!")); ``` 5. 处理事件 在订阅者中,创建一个方法来处理接收到的事件。例如,在Activity中: ``` @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { // Do something with the event Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } ``` 以上就是基于EventBus 3.0的APP开发的基本步骤。通过使用EventBus,你可以轻松地在不同组件之间传递数据,从而实现应用程序中的松散耦合通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值