EventBus3.2使用

268 阅读8分钟

一、 概述

EventBus 是适用于 Android 和 Java 的发布/订阅事件总线。主要功能是替代 Intent、Handler、BroadCast 在 Activity、Fragment、Service 线程之间传递消息。EventBus 能够简化应用组件间的通信,解耦 (有效分离) 事件的发送者和接收者,避免复杂和容易出错的依赖和生命周期问题,开销小,代码更优雅。但是需要注意的是 EventBus 不能用于进程间通信。 Andorid 组件间通信,可能都是用 Handler 消息机制或者广播机制来实现通信,但是它们代码量大,组件上容易产生耦合 。为什么选择使用 EventBus 来做通信?

二、 使用步骤

  1. 定义事件对象 事件对象可以试任意java类型,没有特殊要求,比如String、int、自定义类等。
public class MessageEvent {
    public String type;
}
  1. 在接收消息的页面注册事件
EventBus.getDefault().register(this);

register(Object subscriber):EventBus订阅事件的方法,通过EventBus.getDefault()获取事件总线实例;参数subscriber为订阅者,订阅者有处理事件的方法,并且必须添加@Subscribe注解。 只有注册了订阅事件,才会接收到消息。注意通常根据Activity和Fragment的生命周期注册和注销事件。

  1. 订阅者实现事件处理方法

也称为“订阅者方法”,当发布对应事件类型时,该方法被调用(在接收消息的页面)。

@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event){
    //接收事件后
}
  • @Subscribe: 必须使用@Subscribe注解来定义订阅者方法,否则事件处理方法无法生效。
  • threadMode: 线程模式,表示在哪个线程里面执行,ThreadMode.MAIN表示在主线程执行该方法。
  • onEvent(MessageEvent event): 事件处理方法名onEvent()自定义(即任意取名);参数类型MessageEvent为定义接收事件的对象类型,要与发布事件的类型一致,否则无法接收时间。
  1. 发布事件
EventBus.getDefault().post(Object event);
  • post(Object event): EventBus发送事件的方法,参数event为事件对象,是Object任意类型,这里发送的类型需要与接收时间的类型一致。当前与事件类型匹配的所有已注册的事件都会接收到。
  1. 在接收消息的页面注销(解除注册)事件
EventBus.getDefault().unregister(this);
  • unregister(Object subscriber): 订阅者注销事件的方法,如果事件不需要使用了必须调用该方法注销事件。当消息页面不存在或者不需要事件了注销该事件。 三、 项目实践
  1. 添加依赖
implementation 'org.greenrobot:eventbus:3.2.0'
  1. 定义事件对象
public class MessageEvent {
    public String type;
    public MessageEvent(String type){
        this.type = type;
    }
}

这个类很简单,只定义了一个参数type,构造时传入一个字符串,它是用于我们发送事件的事件对象携带参数的封装类,在下面订阅者方法接收的参数中也是以MessageEvent为接收类型才能接收到。两个类型要一致才能成功的接收到发出的数据。 3. 在接收消息的页面注册和注销事件

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

发布事件前需要明确接收消息的页面已经创建并且注册了时间,另外粘性事件能实现先发布事件,后续再注册事件,这样也能接收事件,后面说明 4. 订阅者实现事件处理的方法

@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event){
    //接收事件后
    Toast.makeText(this,event.type,Toast.LENGTH_SHORT).show();
}
  1. 发布事件
EventBus.getDefault().post(new MessageEvent("2"));

四、 粘性事件的使用

在普通事件中,订阅者(接收消息的页面)要先注册,才能接收到发布的事件;也就是说接收消息的页面还没创建或者未注册订阅者,那么处理事件的方法根本无法接收发送者(发送消息的页面)发布的事件。EventBus提供了一种粘性事件,能在发送事件之后再订阅该事件也能接收到该事件。与普通事件不同,普通事件是先注册后发布,粘性事件可以现发布后注册。

  1. 粘性事件的事件函数处理方法,需要在注解中添加sticky=true标识,表示该事件是粘性事件:
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void onStickEvent(MessageEvent event){
    //接收事件后
    ToastUtils.show(event.type);
}
  1. 使用PostSticky()发布粘性事件:
EventBus.getDefault().postSticky(new MessageEvent("2"));

发布粘性事件后,EventBus将会一直存在粘性事件,在不需要粘性事件的时候需要及时移除,移除的方法有下面几个:

//移除指定的粘性事件 
removeStickyEvent(Object event); 
//移除指定对象类型的粘性事件 
removeStickyEvent(Class<T> eventType);
//移除所有粘性事件 
removeAllStickyEvents();

举例,创建两个Activity,在StickySendActivity中向StickyReceiveActivity发布粘性事件,发布完后跳转到StickyReceiveActivity中,StickyReceiveActivity创建并注册EventBus,订阅粘性事件的处理方法:

public class StickySendActivity extends AppCompatActivity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sticky_send);
        findViewById(R.id.btn_send).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_send://发布事件
                //4.发布粘性事件
                EventBus.getDefault().postSticky("StickySendActivity发送粘性事件");
                startActivity(new Intent(this, StickyReceiveActivity.class));
                break;
        }
    }
}

点击发送粘性事件按钮向StickyReceiveActivity发布粘性事件,发布完后跳转到StickyReceiveActivity中。

public class StickyReceiveActivity extends AppCompatActivity{
    private TextView mTv_content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sticky_receive);
        mTv_content = findViewById(R.id.tv_content);
        //1.注册事件
        EventBus.getDefault().register(this);
    }

    //3.接收StickySendActivity粘性事件处理, sticky = true表示是粘性事件
    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onStickyEvent(String str) {
        //TODO 接收事件后Do something
        mTv_content.setText("onStickyEvent:接收到" + str);
        Toast.makeText(this, "onStickyEvent:接收到" + str, Toast.LENGTH_SHORT).show();
        EventBus.getDefault().removeStickyEvent(this)//移除粘性事件
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //2.反注册事件
        EventBus.getDefault().unregister(this);
    }
}

StickyReceiveActivity 创建并注册 EventBus,订阅粘性事件的处理方法,接收到粘性事件发送的数据,显示在 mTv_content 控件上并吐司提示,然后通过 removeStickyEvent(this) 移除当前的粘性事件。

五、 EventBus的几种线程模式 默认为ThreadMode.POSTING

线程含义特点
POSTING默认线程,表示订阅者将在发布事件的同一线程中被调用适用于不需要主线程就可以在短时间内完成的简单任务,避免了线程切换,开销更小
MAIN表示在Android中,订阅者在Android主线程中被调用如果发布事件的线程是主线程,订阅者的事件处理函数将直接被调用。如果发布事件的线程不是主线程,则将事件加入主线程队列中,排队等待执行;因此这里不能进行耗时操作,注意不能阻塞主线程
MAIN_ORDERED表示在Android中,订阅者在Android主线程中被调用与MAIN不同的是,无论发布事件的线程是在哪个线程,事件都将发送到主线程队列总是排队等待传递。注意不能阻塞主线程
BACKGROUND表示在Android中,订阅者在后台线程中被调用在Android中,如果发布线程不是主线程,订阅者的事件处理函数直接使用该线程,如果发布线程是主线程,那么事件处理函数会开启一个后台线程,有序分发事件,注意不能阻塞后台线程,这里不能进行UI操作;如果不是在Android上,总是使用一个后台线程
ASYNC表示无论发布线程是什么线程,订阅者都会创建一个新的子线程执行使用于耗时操作,尽量避免同时触发大量的耗时较长的异步操作,EventBus使用线程池高效的复用已经完成异步操作的线程

那么说明 POSTING 模式的订阅者处理函数线程与发布线程一致,MAIN 和 MAIN_ORDERED 模式的订阅者处理函数线程为主线程,BACKGROUND 和 ASYNC 模式的订阅者处理函数线程为后台线程。

五、 几种线程模式使用

接收消息页面

//订阅者的接收事件处理函数
//处理函数执行线程与发布线程一致
@Subscribe(threadMode = ThreadMode.POSTING)
public void onEventPosting(MessageEvent event){
    Log.e(TAG,"onEventPosting:" + Thread.currentThread().getName());
}
//处理函数执行线程为主线程
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMain(MessageEvent event){
    Log.e(TAG,"onEventMain:" + Thread.currentThread().getName());
}
//处理函数执行线程为主线程
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onEventMainOrdered(MessageEvent event){
    Log.e(TAG,"onEventMainOrdered:" + Thread.currentThread().getName());
}
//处理函数执行线程为后台线程
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onEventBackground(MessageEvent event){
    Log.e(TAG,"onEventBackground:" + Thread.currentThread().getName());
}
//处理函数执行线程为后台线程
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onEventAsync(MessageEvent event){
    Log.e(TAG,"onEventAsync:" + Thread.currentThread().getName());
}

发送消息页面

EventBus.getDefault().post(new MessageEvent("1"));

打印数据如下

2021-11-30 15:13:09.268 15370-15370/com.htkj.an.myproject E/MainActivity: onEventMain:main
2021-11-30 15:13:09.268 15370-16389/com.htkj.an.myproject E/MainActivity: onEventAsync:pool-1-thread-1
2021-11-30 15:13:09.268 15370-15370/com.htkj.an.myproject E/MainActivity: onEventPosting:main
2021-11-30 15:13:09.268 15370-15370/com.htkj.an.myproject E/MainActivity: onEventMainOrdered:main
2021-11-30 15:13:09.268 15370-16390/com.htkj.an.myproject E/MainActivity: onEventBackground:pool-1-thread-2

可以看出POSTING模式的线程与发布线程一致,都是主线程;MAIN 和 MAIN_ORDERED 模式的线程为主线程,BACKGROUND 和 ASYNC 模式线程为后台线程。

  • 事件的优先级 EventBus支持定义订阅者事件处理方法时指定事件传递的优先级。默认情况下,事件优先级为0,数值越大,优先级越高,在相同线程模式下,优先级高的比优先级低的先收到事件。
@Subscribe(threadMode = ThreadMode.MAIN,priority = 0)
public void onEventMain(MessageEvent event){
    
}

————————————————

参考原文地址

原文链接:blog.csdn.net/liuwg1226/a…