EventBus—使用实践

1. 概述

EventBus是Greenrobot开源组织推出的开源框架,是一个基于发布者/订阅者模式的通信框架,有效地解耦调用者和被调用者。

Githubhttps://github.com/greenrobot/EventBus
官网http://greenrobot.org/eventbus/
优点:

  • 简化组件间的通信;
  • 解耦调用者与被调用者的关系;
  • 避免复杂的关系逻辑与生命周期的问题;
  • 方便切到不同线程上执行任务;

2. 实践

为了方便后面对其源码进行剖析,先理解EventBus怎么使用,官网上对其使用做了详尽的描述。

2.1. 准备工作

2.1.1. 添加依赖
dependencies {
    ...
     'org.greenrobot:eventbus:3.1.1'
}
2.1.2. 注册与解注册

本文例子在Activity的onStart和onStop方法中注册和解注册,两者必须成对存在,否者会造成泄漏。

  • 注册
    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }
  • 解注册
    @Override
    protected void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }

注意事项:

  1. 注册时,要保证订阅者(注册的对象)要订阅事件,否者抛异常;
  2. 成为订阅者的两个条件:a. 注册;b.订阅事件;
  3. 订阅者也可以是发布者;

2.2. 简单使用

2.2.1. 定义事件

定义事件就是创建一个普通的Java对象,没有特别的要求:

public class TextEvent {
    private String mText;

    public TextEvent(String text) {
        this.mText = text;
    }

    public String getText() {
        return mText;
    }

    public void setText(String text) {
        this.mText = text;
    }
}
2.2.2. 订阅事件
    @Subscribe
    public void onHandleTextEvent(TextEvent event){
        mTvResult.setText(event.getText());
    }
2.2.3. 发布事件
EventBus.getDefault().post(new TextEvent("From MainActivity text event"));

2.3. 线程模式

可以在不同的线程发布事件,那么订阅者怎么在不同线程上接收和处理事件呢?EventBus提供了线程模式,可以规定在不同线程下处理事件,一共五种线程模式:

ThreadMode.POSTING:订阅者方法将在发布事件所在的线程中被调用。这是 默认的线程模式;

ThreadMode.MAIN 订阅者方法将在主线程(UI线程)中被调用,如果发布事件的线程是主线程,那么该模式的订阅者方法将被直接调用;

ThreadMode.MAIN_ORDERED 订阅者方法将在主线程(UI线程)中被调用, 与Main模式不同的是,该模式会将事件插入队列当中才发送给订阅者;

ThreadMode.BACKGROUND 订阅者方法将在后台线程中被调用;

ThreadMode.ASYNC 订阅者方法将在一个单独的线程中被调用;

public enum ThreadMode {
    POSTING,
    MAIN,
    MAIN_ORDERED,
    BACKGROUND,
    ASYNC
}
2.3.1. 使用线程模式
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onHandleToastWorkerEvent(ToastWorkerEvent event){
        Log.i(TAG, "Handle ToastWorkerEvent current thread:" + Thread.currentThread().getId());
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onHandleToastMainEvent(ToastMainEvent event){
        Log.i(TAG, "Handle ToastMainEvent current thread:" + Thread.currentThread().getId());
    }
2.3.2. 点击推送事件
    public void onClick(View view) {
        switch (view.getId()) {
       
            case R.id.bt_send_toast_event_worker_thread:
                Log.i(TAG, "Post ToastWorkerEvent current thread:" + Thread.currentThread().getId());
                EventBus.getDefault().post(new ToastWorkerEvent());
                break;
            case R.id.bt_send_toast_event_main_thread:
                Log.i(TAG, "Post ToastMainEvent current thread:" + Thread.currentThread().getId());
                EventBus.getDefault().post(new ToastMainEvent());
                break;
        }
    }

结果打印:

12-08 10:41:11.550 23954-23954/com.wuzl.eventbus I/MainActivity: Post ToastWorkerEvent current thread:2
12-08 10:41:11.562 23954-24547/com.wuzl.eventbus I/MainActivity: Handle ToastWorkerEvent current thread:1780

12-08 10:41:30.336 23954-23954/com.wuzl.eventbus I/MainActivity: Post ToastMainEvent current thread:2
12-08 10:41:30.337 23954-23954/com.wuzl.eventbus I/MainActivity: Handle ToastMainEvent current thread:2

2.4. 事件优先级与取消事件下发

通过priority 定义处理事件的优先级,并可以取消事件的下发,例子中高优先级的回调先被执行,然后该事件的下发,后续其他订阅者将无法收到该事件。

    @Subscribe(priority = 10)
    public void onHandleTextEvent(TextEvent event){
        mTvResult.setText(event.getText());
        EventBus.getDefault().cancelEventDelivery(event) ;
    }

    @Subscribe(priority = 1)
    public void onHandleLowPriorityTextEvent(TextEvent event){
        mTvResult.setText(event.getText()+" LowPriority");
    }

2.5. 粘性事件(Sticky Event)

事件已经发布了,后面注册的订阅者依旧可以接收到该事件:

2.5.1. 发布粘性事件
EventBus.getDefault().postSticky(new StickyEvent("Sticky Event from MainActivity"));
2.5.2. 接收粘性事件
    @Subscribe(sticky = true)
    public void onHandleStickyEvent(StickyEvent event) {
        mTvResult.setText(event.getText());
    }

本文的实例代码,先发布粘性事件,然后再接收粘性事件的StickyActivity,代码如下:

MainActivity:

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_send_sticky_event:
                EventBus.getDefault().postSticky(new StickyEvent("Sticky Event from MainActivity"));
                break;
            case R.id.bt_open_sticky_event_activity:
                startActivity(new Intent(this,StickyActivity.class));
                break;
        }
    }

StickyActivity:

public class StickyActivity extends AppCompatActivity {

    private TextView mTvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sticky);
        mTvResult = (TextView) findViewById(R.id.tv_sticky_event_result);
        EventBus.getDefault().register(this);
    }

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

    @Subscribe(sticky = true)
    public void onHandleStickyEvent(StickyEvent event) {
        mTvResult.setText(event.getText());
    }
}

注意事项:粘性事件接收实在注册的过程中,开发时注意过早注册和接收粘性事件,是否会因为一些参数未初始化导致出现异常。
验证结果
image

2.6. 索引加速(Subscriber Index)

为了提高性能,EventBus 3.0引入了索引加速的功能,大幅度地提高的性能,其实就是利用了APT在编译阶段提前构建订阅者的索引列表,后续源码剖析中会分析到

2.6.1. 配置
defaultConfig {
    // 自定义APT自动生成的订阅者索引类    
    javaCompileOptions {
        annotationProcessorOptions{
            arguments = [ eventBusIndex : 'com.wuzl.eventbus.TestEventBusIndex' ]
        }
    }
}
    
// 配置APT processor    
dependencies {
    implementation 'org.greenrobot:eventbus:3.1.1'
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}
2.6.2. 使用
  1. 将索引加速应用到全局EventBus:
EventBus.builder().addIndex(new TestEventBusIndex()).installDefaultEventBus(); 
EventBus eventBus = EventBus.getDefault();
  1. 将索引加速应用到局部EventBus
EventBus eventBus = EventBus.builder().addIndex(new TestEventBusIndex()).build();

2.7. 示例代码

MainActivity:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    private TextView mTvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.builder().addIndex(new TestEventBusIndex()).installDefaultEventBus();
        mTvResult = (TextView) findViewById(R.id.tv_result);
    }

    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

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

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_send_text_event:
                EventBus.getDefault().post(new TextEvent("From MainActivity text event"));
                break;
            case R.id.bt_send_toast_event_worker_thread:
                Log.i(TAG, "Post ToastWorkerEvent current thread" + Thread.currentThread().getId());
                EventBus.getDefault().post(new ToastWorkerEvent());
                break;
            case R.id.bt_send_toast_event_main_thread:
                Log.i(TAG, "Post ToastMainEvent current thread" + Thread.currentThread().getId());
                EventBus.getDefault().post(new ToastMainEvent());
                break;
            case R.id.bt_send_sticky_event:
                EventBus.getDefault().postSticky(new StickyEvent("Sticky Event from MainActivity"));
                break;
            case R.id.bt_open_sticky_event_activity:
                startActivity(new Intent(this,StickyActivity.class));
                break;
        }
    }

    @Subscribe(priority = 10)
    public void onHandleTextEvent(TextEvent event){
        mTvResult.setText(event.getText());
        EventBus.getDefault().cancelEventDelivery(event);
    }

    @Subscribe(priority = 1)
    public void onHandleLowPriorityTextEvent(TextEvent event){
        mTvResult.setText(event.getText()+" LowPriority");
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onHandleToastWorkerEvent(ToastWorkerEvent event){
        Log.i(TAG, "Handle ToastWorkerEvent current thread" + Thread.currentThread().getId());
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onHandleToastMainEvent(ToastMainEvent event){
        Log.i(TAG, "Handle ToastMainEvent current thread" + Thread.currentThread().getId());
    }
}

3. 结语

EventBus的使用非常简单,并且可以让我们代码变得更加简洁和清晰,但是有个缺点,随着业务量的增加,需要定义的事件类会越来越多,难于管理。
EventBus就是一家杂志社,订阅者可以订阅自己需要的内容(事件),一旦有新的杂志发布,订阅者就能收到订阅消息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值