Android 模块通信—— EventBus

    EventBus 是 Android 的一个基于发布/订阅模式的轻量级框架,用于 Android 解耦的事件传递,开源地址。

  这是官方地址的一个说明图:

Android 模块通信—— EventBus_第1张图片

    可以看到,它是通过发布者的 post() 来发送时间,订阅者的 onEvent() 来响应事件,我们来看看怎么使用 EventBus:

    第一步当然是导入它的依赖库:

compile 'org.greenrobot:eventbus:3.1.1'

    首先我们需要注册 EventBus,注册有两种方式,一般使用第一种默认方式。

// 第一种,在 onCreate() 方法中注册
        EventBus.getDefault().register(this);
        // 第二种
        EventBusBuilder busBuilder = EventBus.builder()
                // 设置线程池,默认为动态多线程的线程池
                .executorService(Executors.newSingleThreadExecutor())
                // 事件是否继承,默认 true
                .eventInheritance(true);
        EventBus eventBus = busBuilder.build();
        eventBus.register(this);

    这里的事件是否继承是什么意思呢?如果事件 A 继承自事件 B,当发布者发布事件 A 时,如果可继承为 true,那么订阅者 B 也是可以收到事件 A 的,反之则接收不到。

    我们需要注意的是,我们一定要记得在 onDestroy() 中去取消注册 EventBus:

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

    首先我们先来定义一个事件:    

public class Event {
    private String data;

    public Event(String data){
        this.data = data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }
}

然后我们需要发送事件:

// 发送事件
        EventBus.getDefault().post(new Event("响应事件"));

    响应事件:

// 通过注解方式响应事件
    @Subscribe(threadMode = ThreadMode.POSTING,priority = 1,sticky = false)
    public void onEvent(Event event ){
        // 响应事件 
    }

    这里的三个参数是什么意思呢?ThreadMode 是线程模式,我们看它的源码是一个枚举,有五种类型:

类型    说明
POSTING                 发布者在哪个线程发布事件,订阅者就在哪个线程响应事件
MAIN      不管发布者在哪个线程发布事件,订阅者都在主线程响应事件。不同的是:当发布者在主线程时,订阅者会直接阻塞线程来响应事件,而当发布者在其它线程时,订阅者就会非阻塞的排队等待响应事件

MAIN-ORDERED                               

不管发布者在哪个线程,订阅者都在主线程响应事件,与 MAIN 不同的是,MAIN-ORDERED 一直都是非阻塞的形式等待响应事件
BACKGROUND 如果发布者不在主线程,那么订阅者直接在发布者的线程响应事件,如果发布者在主线程,那么订阅者就会使用一个单独的后台线程按序响应事件
ASYNC  不管发布者在哪个线程,订阅者都是在一个独立的线程里面响应事件,发布者不会等待订阅者的响应,所以这种模式一般用于响应的事件比较耗时的情况

    priority 是优先级,默认为 0,越大优先级越高;sticky 代表是不是粘性事件,默认为 false。 

    然后我们在另一个没有与发布者有任何代码关联的 Activity 来发送一个事件: 

postEvent=findViewById(R.id.btn_post_event);
        postEvent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new Event("响应事件"));
            }
        });

    效果图:

Android 模块通信—— EventBus_第2张图片

    可以看到我们发送了事件过后,马上就响应了该事件。

    上面我们说了一个黏性事件,这个是什么意思呢?我们来举一个栗子,大家想一下:如果我们发布了一个事件,但是订阅了这个事件的 Activity 还没有启动,那它肯定是不能响应该事件的,我们可以看看,我们在第一个页面发送事件 B,在第二个页面响应事件 B:

// 第一个 Activity 页面发送事件 B
        postEvent=findViewById(R.id.btn_post_event_b);
        postEvent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new EventB("响应事件"));
            }
        });
// 第二个 Activity 页面响应事件 B
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onEvent(EventB eventB){
        Toast.makeText(SubscriberEventActivity.this,eventB.getData(),Toast.LENGTH_SHORT).show();
    }

    效果图:

Android 模块通信—— EventBus_第3张图片

    我们可以看到,第二个页面是没有响应事件的,这个时候黏性事件的作用就出来了,黏性事件的作用就是只要是发布者发送了事件,不管当时订阅者有没有接收到这个事件,只要订阅者来订阅这个事件就能接收到这个事件,怎么实现呢?

// 第一个 Activity 页面发送事件 B
        postEvent=findViewById(R.id.btn_post_event_b);
        postEvent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 通过 postSticky() 来发送粘性事件
                EventBus.getDefault().postSticky(new EventB("响应事件B"));
            }
        });
// 第二个 Activity 页面响应事件 B,设置 sticky 为 true
    @Subscribe(threadMode = ThreadMode.POSTING,sticky = true)
    public void onEvent(EventB eventB){
        Toast.makeText(SubscriberEventActivity.this,eventBus.getData(),Toast.LENGTH_SHORT).show();
    }

    效果图:

Android 模块通信—— EventBus_第4张图片

    可以看到,就算我们当时不能订阅该事件,只要我们后面订阅该事件就能就收到该事件,但是就又出现一个问题了,它会只要重新进一次页面,重新订阅一次就会响应一次事件,那怎么办呢?我们就可以移除黏性事件:

 // 第二个 Activity 页面响应事件 B,设置 sticky 为 true
    @Subscribe(threadMode = ThreadMode.POSTING,sticky = true)
    public void onEvent(EventB eventB){
        Toast.makeText(SubscriberEventActivity.this,eventB.getData(),Toast.LENGTH_SHORT).show();
        // 我们在响应该事件后就移除该黏性事件
        EventBus.getDefault().removeStickyEvent(EventB.class);
    }

    效果图:

Android 模块通信—— EventBus_第5张图片

    可以看到,我们移除黏性事件过后,就不会再响应该事件了。

    EventBus 的简单使用就是这么多,那么我们使用 EventBus 需要注意什么呢?

    1. EventBus 一般用于模块间通信,如果模块内能够适应 Intent、接口等通信时优先使用 Intent 通信

    2. 因为模块开发一般是协同开发,所以对于事件的定义和响应要避免重复和包含

    3. 因为 EventBus 是解耦的,所以就不要在响应事件里面发布事件来增加耦合性

    4. 因为注册 EventBus 是默认动态多线程的线程池,所以要避免进行一些大量耗时操作的发布

    5. 如果按照顺序处理事件,尽量保证发布者和订阅者在同一种线程,即使用 ThreadMode.POSTING 

    6. 要记得取消注册 EventBus,要不然它对 Activity 的持有会造成内存泄露




你可能感兴趣的:(Android,小题)