消息传递机制之EventBus的使用详细

本文介绍了EventBus的由来、作用,详细阐述了其主要角色、使用方法、线程模型、实例演示、粘性事件特性,以及优缺点和与2.x版本的对比。EventBus简化了Android组件间通信,但过多的事件类可能增加维护成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 EventBus是怎样管理事件总线的, 是不是最佳处理消息的方案?让我们一同来学习和认识.

EventBus由来

    在面对应用程序内组件间, 组件与后台线程间的通信. 又如我们在处理耗时操作时, 等到耗时操作完成后通过Handler或者Broadcast去更新UI, 但是面对多个Activity之间需要通过Listener通信完成. 但是这些问题我们可以通过EventBus来完成.它是通过发布/订阅的方式来管理事件总线 .通过注解和反射机制将订阅者连同订阅函数保存起来, 然后在发送订阅的时候遍历订阅函数数组进行调用, 但是这种形式会影响到EventBus的执行效力.

EventBus的介绍

    EventBus出自greenrobot, 与GreenDao是一家. 而EventBus3.0框架采用了建造者模式, 并加入注解, 通过注解的方式告知订阅函数运行在哪一个线程中.

EventBus主要角色

  •     Event 传递的事件对象
  •     Subscriber 事件的订阅者
  •     Publisher事件的发布者
  •     ThreadMode 定义函数在那种线程中执行

官网给出的各种角色的协作图


EventBus使用

  1. 在build.gradle中添加引用
compile 'org.greenrobot:eventbus:3.0.0'

    2. 定义一个事件类型

 public class EventInfoBean {
     public String msg;
     public EventInfoBean(String msg) {
         this.msg = msg;
      }
  }

    3.订阅事件

EventBus.getDefault().register(this);

    4. 发布事件

EventBus.getDefault().post(new 	EventInfoBean("eventBus发送的消息"))

    5. 解除订阅(一般放在onDestroy()中)

EventBus.getDefault().unregister(this);
    6.订阅事件处理
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMainThread(EventInfoBean info) {
        Toast.makeText(getApplicationContext(), "接收到的消息..." + info.msg, Toast.LENGTH_SHORT).show();
    }

    7.订阅事件的优先级

    EventBus事件的优先级类似于广播的优先级, 优先级越高优先得到消息

    @Subscribe(threadMode = ThreadMode.MAIN,priority = 100)
    public void onDataSynEvent(EventInfoBean event) {
        Log.e(TAG, "event---->" + event.msg);
    }

    8.终止事件传递

    EventBus在发送有序广播的时候可以终止广播的往下传递

 EventBus.getDefault().cancelEventDelivery(event) ;

    9. 代码混淆

-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

EventBus线程模型说明

    ThreadMode.MAIN  

        无论任何线程中发布事件, 事件处理函数都会在main线程中执行.该方法可以用来更新UI, 但是不能处理耗时操作

    ThreadMode.BACKGROUND

        如果发布事件是在UI线程中发布, 那么事件处理函数会在新的线程中运行, 如果发布事件本来就在子线程中发布的, 那么事件处理函数在发布事件的线程中执行. 此事件处理函数不可以进行UI更新操作

    ThreadMode.POSTING

        事件处理和事件发布在同一个线程中. 在事件处理函数中尽量避免执行耗时操作, 因为它会阻塞事件的传递, 有可能会引起ANR

    ThreadMode.ASYNC

        不管事件在哪个线程中发布, 该事件处理函数都会在新建的子线程中执行. 事件处理函数中禁止UI更新操作

实例

    事件处理函数

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEventMain(FirstEvent firstEvent) {
    Log.d(TAG, "接收到的消息.1.." + Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessageEventAsync(FirstEvent firstEvent) {
    Log.d(TAG, "接收到的消息.2.." + Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEventBackground(FirstEvent firstEvent) {
    Log.d(TAG, "接收到的消息.3.." + Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessageEventPosting(FirstEvent firstEvent) {
    Log.d(TAG, "接收到的消息.4.." + Thread.currentThread().getName());
}

从UI线程中发布事件

    发布事件

send.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        EventBus.getDefault().post(new FirstEvent("在同一个线程中执行"));
    }
});

    输出log

02-27 10:26:29.727 14358-14358/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.1..main
02-27 10:26:29.727 14358-14358/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.4..main
02-27 10:26:29.728 14358-14420/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.2..pool-1-thread-1
02-27 10:26:29.729 14358-14421/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.3..pool-1-thread-2

从子线程中发布事件

    发布事件

send.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                EventBus.getDefault().post(new FirstEvent("在同一个线程中执行"));
            }
        }).start();
    }
});

输出log

02-27 10:30:45.027 14523-14541/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.3..Thread-799
02-27 10:30:45.027 14523-14541/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.4..Thread-799
02-27 10:30:45.027 14523-14542/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.2..pool-1-thread-1
02-27 10:30:45.036 14523-14523/com.quanzi.eventbusdemo D/SameThreadActivity: 接收到的消息.1..main

EventBus粘性事件

    EventBus的粘性事件类似于广播中的粘性广播. 粘性广播在实际开发中使用的比较少.粘性广播中订阅/解除订阅和普通事件一样, 但是在处理订阅函数时需要添加注解 sticky = true

    处理粘性事件

 @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void onDataSynEvent(FirstEvent event){
        Log.d(TAG,"sticky..." + event.getMsg() + "..." + Thread.currentThread().getName());
    }

    发送粘性事件

 EventBus.getDefault().postSticky(new FirstEvent("粘性事件..."));

     移除粘性事件

        粘性广播属于常驻广播, 如果不需要可以移除粘性事件

    EventBus.getDefault().removeStickyEvent(new FirstEvent());

        或调用移除所有粘性事件

    EventBus.getDefault().removeAllStickyEvents();

EventBus的优缺点

    优点 : 简化了各组件间的通信方式, 实现了解耦让业务代码更加简洁, 可以动态设置事件处理线程以及优先级

    缺点 : 每一个事件必须自定义一个事件类, 造成事件类过多, 从而增加了维护的成本

EventBus3.0与2.X比较

1.代码更加简洁

2.性能更优. 由于EventBus 2.x 是采用反射的方式对整个注册类中的所有方法进行扫描来完成注册,因此在性能上有所影响。而EventBus3.0提供EventBusAnnotationProcessor注解处理器在编译期通过读取Subscribe注解并解析、处理其中所包含的信息,再生成java类来保存所有订阅者的信息,从而比在运行时使用反射来获得这些订阅者的信息速度要快

以上是我个人对EventBus3.0的一些认识和理解,要是有什么地方不对的,欢迎各位同仁指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值