EventBus 3.0用法总结

一.使用步骤

  1. 添加依赖(Add EventBus as a denpendency).
    Modulebuild.gradle文件dependencies闭包下添加依赖:
 compile 'org.greenrobot:eventbus:3.0.0'
  1. 注册与取消注册订阅者( Register & unregister subscriber).
    订阅者就是接受消息的一方,通常是activity或者fragment.我们分别在他们的onStart()方法中进行注册,onStop()方法取消注册,这样就可以使Subscribersactivityfragment的生命周期保持一致.直接写在抽取的BaseActivity或者BaseFragment里,子类里就不用再写了:
 @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }
  1. 定义事件(Define event).
    有了订阅者,接下来就需要订阅的内容了,也就是我们想要传递的消息,这里称为事件(Event).事件可以是任意Java对象,不论是基本数据类型,字符串还是我们自己定义的Bean对象,都可以传递给订阅者.
  2. 发送事件(Post event).
    EventBus把事件发送和接收的具体方法都封装好了,我们直接将事件post出去即可.这里我新开了一个线程,把字符串作为事件,每300ms发送一个出去:
new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(300);
                EventBus.getDefault().post(i + "");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}).start();
  1. 处理事件(Define subscriber).
    最后我们在Subscriber里写一个订阅方法来处理接收到的事件,与2.x时期相比,EventBus 3.0通过注解来定义这个方法,而且对命名不再有任何要求,方便了很多.首先在注解里设定处理事件的线程,然后将前面发送的的事件作为参数传递进来,不同的订阅方法就是根据这个参数的类型来接收对应的事件.这里我用一个Toast将接收到的字符串打出来,所以threadMode选择的是ThreadMode.MAIN:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(String s) {

    if (toast != null) {
        toast.setText(s);
    } else {
        toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
    }
    toast.show();
}

二.Thread Mode的选择

上面例子注解里的threadMode是指处理事件的线程.EventBus 给我们提供的线程类型一共有四种:

  1. POSTING
    如果没在注解里设定线程的话,默认为POSTING,它与发送事件线程是同一线程.
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
      log(event.message);
}
  1. MAIN
    顾名思义,主线程.
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
      textView.setText(event.message);
}
  1. BACKGROUND
    如果发送事件的线程是主线程,则另开一个线程来处理事件,如果发送事件的线程不是主线程,则直接在发送事件的线程处理事件.
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
      saveToDisk(event.message);
}
  1. ASYNC
    不论发送事件的线程是什么线程,都会使用其他的线程来处理事件.前面三种类型线程我们需要在线程里迅速完成事件的处理,避免线程阻塞,而ASYNC类型线程则可以用来处理诸如网络访问等耗时操作.EventBus采用的是一个线程池来复用执行完毕的异步线程,我们应该注意避免同时启用大量ASYNC线程.
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
      backend.send(event.message);
}

三.粘性事件(Sticky Event)

粘性事件可以在发布(post)后暂不处理这个粘性事件,一段时间之后再处理,此时粘性事件信息为最新的粘性事件信息.下面通过一个例子可以直接比较粘性事件和非粘性事件的异同.

MainActivity界面如下:

EventBus 3.0用法总结_第1张图片
G 1

首先,在MainActivity注册与取消注册订阅,订阅方法里将发送的事件信息显示在一个TextView上:

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(String s) {
        textMessge.setText(s);
    }

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

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

然后,在MainActivity添加三个按钮,前两个分别用来向SecondActivity发送粘性事件和非粘性事件,第三个按钮跳转到SecondActivity.

    @Override
            public void onClick(View v) {
                switch (v.getId()) {
                    case R.id.btn_send_sticky:
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                for (int i = 0; i < 10; i++) {
                                    try {
                                        Thread.sleep(200);
                                        EventBus.getDefault().postSticky(i + "");
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }).start();
                        break;
                    case R.id.btn_send_normal:
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                for (int i = 0; i < 10; i++) {
                                    try {
                                        Thread.sleep(200);
                                        EventBus.getDefault().post(i + "");
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }).start();
                        break;
            case R.id.btn_to_activity2:
                startActivity(new Intent(this,SecondActivity.class));
                break;
        }

接下来,在SecondActivity注册与取消注册订阅,并定义两个订阅方法,分别接收粘性事件和非粘性事件,并显示在对应的TextView上:

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

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

    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void showStickyProgress(String stickyEvent){
      
        textSticky.setText("sticky: "+stickyEvent);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void showNormalProgress(String normalEvent){
        textNormal.setText("normal: "+normalEvent);
    }

SecondActivity界面如下:

EventBus 3.0用法总结_第2张图片
G 2

把程序跑起来后,在MainActivity点击"发送NORMAL EVENT",可以看到顶部显示数字,等数字停止变化后,进入SecondActivity,没有任何显示.返回MainActivity,点击"发送STICKY EVENT",等数字停止变化后进入SecondActivity,可以看到sticky后显示了数字9.这是因为在MainActivity发送事件之前已经完成了对订阅的注册,所以不论是postSticky()还是直接post(),都会在MainActivity顶部的TextView里显示发送的事件内容.而进入SecondActivity之前,SecondActivity的订阅还没有注册,进入SecondActivity以后才注册订阅,此时距事件发送已经很久了.

EventBus 3.0用法总结_第3张图片
G 3

在上图可以看到,发送粘性事件之后,SecondActivity显示事件信息,当我返回MainActivity再进入SecondActivity后,依然显示刚才的事件信息,这是因为EventBus把该事件对象存在内存里,只有当有了新的粘性事件信息,才会再次变化.那如果不想在再次进入SecondActivity后显示事件信息该怎么办呢?刚才粘性事件的获取我们是通过注解自动获取的,EventBus还给我们提供了手动获取和移除粘性事件的方法,所以只要将最后一次粘性事件移除,并清除掉TextView里的内容就可以了:

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_clean:

                String stickyEvent = EventBus.getDefault().getStickyEvent(String.class);
                if (stickyEvent != null) {
                    EventBus.getDefault().removeStickyEvent(stickyEvent);
                    textSticky.setText("sticky: ");
                }
                break;
        }
    }
EventBus 3.0用法总结_第4张图片
G 4

其实,removeStickyEvent(stickyEvent)返回的就是之前粘性事件,所以刚才的代码可以直接写成:

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_clean:

                String stickyEvent = EventBus.getDefault().removeStickyEvent(String.class);
                if (stickyEvent != null) {
                    textSticky.setText("sticky: ");
                }
                break;
        }
    }

效果和前面的代码是一样的.

四.优先级与取消事件传递(Priorities & Event Cancellation)

这里优先级的概念与有序广播类似,订阅者的优先级越高(值越大),越先接收到事件.优先级直接写在注解里[1]:

@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
    ...
}

取消订阅也很简单,直接在订阅方法里调用以下方法即可:

EventBus.getDefault().cancelEventDelivery(event) ;

如果我们在高优先级的订阅方法里取消了对某事件的订阅,那么事件传递就会终止,低优先级的订阅方法将不会再接收到事件.


  1. 优先级对不同线程类型的订阅者没有任何影响! ↩

你可能感兴趣的:(EventBus 3.0用法总结)