原创

Android EventBus3.0 深入了解

通过上一篇文章《EventBus 3.0相见恨晚》对EventBus3.0的原理及使用方法有了简单了解。

下面就其原理和使用方法做更深入细致的了解。

EventBus设计模式

EventBus is an open-source library for Android using the publisher/subscriber pattern for loose coupling

这句话是greenrobot官网对EventBus的解释。

EventBus是一个针对Android为了松耦合的基于事件发布/订阅模式(观察者模式)的开源库。

Android EventBus3.0 深入了解

框架

从上图我们可以看到EventBus的设计结构非常简单。

EventBus 使用方式

订阅者方法详细用法

从之前对EventBus的Demo我们可以看到,使用EventBus的关键是订阅者方法的实现,也就是事件处理方法onMessageEvent的实现。这个方法,才是我们处理数据、实现UI更新的关键。

 @Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 1)
    public void onMessageEvent(MessageEvent event) {
        tv.setText(event.message);
    }

这里再强调一遍,这个订阅者方法一定要添加@Subscribe这个注解,这个注解的完整参数如上,后面是一些可选的参数。下面就各个参数做一下分析:

EventBus的ThreadMode总共有四种,并且都是在订阅者中的@Subscribe里进行制定的。下面就来看一下这四种ThreadMode。

四种threadMode模式

  • ThreadMode: POSTING
            这时候订阅者执行的线程与事件的发布者所在的线程为同一个线程。也就是说事件由哪个线程发布的,订阅者就在哪个线程中执行。这个也是EventBus默认的线程模式;由于没有线程的切换,也就意味消耗的资源也是最小的。如果一个任务不需要多线程的,也是推荐使用这种ThreadMode的。

我们之前的Demo就是这样,事件发送是在SecondActivity的主线程,那么onMessageEvent在默认情况下必然会在主线程执行。

  • ThreadMode: MAIN
            从它的名字就很容易可以看出,他是在Android的主线程中运行的。如果提交的线程也是主线程,那么他就和ThreadMode.POSTING一样了。当然在这里由于是在主线程中运行的,所以在这里就不能执行一些耗时的任务。

还是之前的Demo,我们在SecondActivity中实现登录操作,正常情况下这必然是个网络请求,而这个网络请求必然不会在主线程(UI线程)中发生,所以,当我们完成网络请求发布事件的时候,发布事件所在的线程就不再是UI线程了,我们的onMessageEvent的ThreadMode就不能为默认值,必须指定为MAIN,确保其在主线程进行对UI的操作。

  • ThreadMode: BACKGROUND
            这种模式下,我们的订阅者将会在后台线程中执行。如果发布者是在主线程中进行的事件发布,那么订阅者将会重新开启一个子线程运行,若是发布者在不是在主线程中进行的事件发布,那么这时候订阅者就在发布者所在的线程中执行任务。

这种情况,一般是我们需要在订阅者方法中进行耗时的操作。

  • ThreadMode: ASYNC
            在这种模式下,订阅者将会独立运行在一个线程中。不管发布者是在主线程还是在子线程中进行事件的发布,订阅者都是在重新开启一个线程来执行任务。

这里我们可以简单的测试一下,加深理解:

下面代码用4种不同的Thread模式订阅同一事件MessageEvent

@Subscribe(threadMode = ThreadMode.PostThread)
public void onMessageEventPostThread(MessageEvent messageEvent) {
    Log.e("PostThread", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.MainThread)
public void onMessageEventMainThread(MessageEvent messageEvent) {
    Log.e("MainThread", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onMessageEventBackgroundThread(MessageEvent messageEvent) {
    Log.e("BackgroundThread", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.Async)
public void onMessageEventAsync(MessageEvent messageEvent) {
    Log.e("Async", Thread.currentThread().getName());
}
  • 在主线程发布事件:
Log.e("postEvent", Thread.currentThread().getName());
EventBus.getDefault().post(new MessageEvent());

看一下日志输出:

Android EventBus3.0 深入了解

主线程中发布事件

可以看出,在主线程发布事件,那么Post和Main 模式下,订阅者方法也是在主线程执行,其他两种模式下分别是独立的线程。

  • 在子线程发布事件
    new Thread(new Runnable() {
                  @Override
                  public void run() {
                      Log.e("postEvent", Thread.currentThread().getName());
                      EventBus.getDefault().post(new MessageEvent());
                  }
              }).start();
    看一下日志输出:

Android EventBus3.0 深入了解

子线程发布事件

子线程发布事件时,只有ThreadMode 为MAIN时,订阅者方法才会在主线程执行。其余都是在独立的线程。

sticky的意义

这个单词sticky的意思是粘贴性,这里的意思就是在发送事件之后再订阅该事件也能收到该事件
默认为false。

priority 的意义

这个priority的意义是优先级,这里主要说一下结论和注意事项

  • 优先级高(priority值大)的将会首先接收到发布者所发布的事件
  • 优先级只是针对于相同的ThreadMode中
  • 默认的优先级为0

平时使用时,可以根据实际需求做调整。

订阅者索引相关

在性能方面,EventBus 3由于使用了注解,比起使用反射来遍历方法的2.4版本逊色不少。但开启索引后性能远远超出之前的版本。下面就来看一下对于EventBus的另一种使用方式。

在Project的build.gradle中添加如下代码:

buildscript {
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

然后在app的build.gradle中添加如下代码:

apply plugin: 'com.neenbedankt.android-apt'

dependencies {
    compile 'org.greenrobot:eventbus:3.0.0'
    apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
apt {
    arguments {
        eventBusIndex "com.example.myapp.MyEventBusIndex"
    }
}

重新rebuild之后会在build目录下面生成MyEventBusIndex文件,文件名可以自定义。下面就来看一下如何使用这个MyEventBusIndex.我们可以自定义设置自己的EventBus来为其添加MyEventBusIndex对象。代码如下所示:

EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

我们也能够将MyEventBusIndex对象安装在默认的EventBus对象当中。代码如下所示:

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();

剩下对于EventBus的用法则是一模一样。当然也建议通过添加订阅者索引这种方式来使用EventBus,这样会比通过反射的方式来解析注解效率更高。

关于EventBus的思考

不使用EventBus的前提下,在Android内部各个组件的交互通信可以说是杂乱无章,各种接口定义,注册、回调。搞得整个代码有着很严重的耦合,接口中多一个参数,参数类型变化都会导致很多地方要改。

Android EventBus3.0 深入了解

传统的组件交互

这种思路注定了随着项目越来越庞大,耦合会越发的严重,所以势必需要一种新的思路来解决这个问题。

而EventBus的出现,很好的解决了这个问题

Android EventBus3.0 深入了解

EventBus

从这两幅图,我们可以清晰的感受到,EventBus给我们代码整体的结构带来多么大的益处,单从图上就可以看到明显减少了各个组件之间的耦合;同时从代码角度出发,EventBus短短几行代码,就可以实现之前通过接口-注册接口-回调 等一系列的工作才能完成的工作量。

当然,凡事要好必然有坏,EventBus使用方式的简单,也会导致我们在出现问题时无从下手,这就需要长时间的积累经验了。但是总的来说,还是利大于弊吧,所以当我们项目有大量的事件交互时,EventBus不失为一种好的选择!


来自:http://www.jianshu.com/p/dbdb92f6f0e2

 

正文到此结束
Loading...