Android应用篇 - 观察者、EventBus、本地广播的区别

Android应用篇 - 观察者、EventBus、本地广播的区别_第1张图片

这篇文章来分析下观察者、EventBus 和本地广播的区别。评价某种方式优劣,有很多种指标,包括空间、时间等性能因素,还有代码的复杂程度,同整个程序的相性等等。

 

目录:

  1. 本地广播
  2. EventBus
  3. 观察者

 

 

1. 本地广播

优点:

  • 一般认为本地广播是三种方式中消耗时间、空间最多的一种方式,但也是同 Android 相对最好的方式。因为广播属于 Android 四大组件之一,在 BroadcastReceiver 中的 onReceive() 方法中可以获得 Context、Intent 参数。持有这两个参数便可以调用许多 Android sdk 中的方法,这一优势另外两种方式很难弥补的,无论是 EventBus 还是观察者,需要获得 Context 的话,往往都需要进行复杂的参数传递或者是依赖注入。
  • 本地广播另外的一个优点是,许多系统级的事件都是使用广播来进行通知的,像常用的电量变化、网络状态变化、短信发送接收的状态等等。这就使得与 Android 系统相关的通知,广播往往成了唯一的选择。

缺点:

  • 但这并不意味着 Android 系统中的通知都应该使用广播,因为相对于其它的方式而言,广播是重量级的、消耗资源较多的方式。广播的优势体现在它与 Android sdk 连接的更紧密,当我们需要同 Android 交互的时候,广播提供的便捷性抵消掉了它过多的资源消耗。但是对于不需要同 Android 交互或是只做很少的交互的时候,使用广播往往是一种浪费。
  • 并且在广播中有一个常见的坑:错误的使用 BroadcastReceiver 的 Context。在 Android 的 Application、Activity、Service、ContentProvider、BroadcastReceiver 中都可以获得对应的 Context,但它们并不完全相同。Activity 的 Context 所能做的事是最全的,而其它组件中的 Context 都或多或少的有着功能残缺。就拿常见的弹出 Dialog 来说,不知道有多少新手试图使用非 Activity 的 Context 创建 Dialog 最终无功而返。另外,使用 BroadcastReceiver 等非 Activity 组件的 Context启动 Activity 也有可能造成隐蔽的错误:当使用非 Activity 组件的 Context 启动 Activity 时,如果不指定 flag 的话,默认会创建一个新的 task,而使用 Activity 的 Context 并且不指定 flag 的话,默认会使用原 task。

 

 

2. EventBus

EventBus 作为 Android 开发中常用的框架,拥有着许多优点:

  • 调度灵活,不依赖于 Context,使用时无需像广播一样关注 Context 的注入与传递。
  • 父类对于通知的监听和处理可以继承给子类,这对于简化代码至关重要。
  • 通知的优先级,能够保证 Subscriber 关注最重要的通知。
  • 粘滞事件 (sticky events) 能够保证通知不会因 Subscriber 的不在场而忽略。

可继承、优先级、粘滞,是 EventBus 比之于广播、观察者等方式最大的优点,它们使得创建结构良好组织紧密的通知系统成为可能。使用简单。EventBus 的 Subscriber 注册非常简单,调用 EventBus 对象的 register() 方法即可,如果不想创建 EventBus 还可以直接调用静态方法 EventBus.getDefault() 获取默认实例,Subscriber 接收到通知之后的操作放在 onEvent 方法里就行了。成为 Publisher 的过程就更简单了,只需要调用合适的 EventBus (自己创建的或是默认的) 的 post 方法即可,快速且轻量。

EventBus 的缺点主要集中在它现阶段的实现方式,2.4.0 版是利用反射来实现的,后来改成 APT 实现。在 Subscriber 注册的时候,Subscriber 中的方法会被遍历查找以 onEvent 开头的 public 方法。这将带来一些问题,一旦对代码进行混淆,就无法查找到了,所以一个程序用到了 EventBus 又需要进行代码混淆时,就得设置混淆规则:

     -keepclassmembers class ** {
         public void onEvent*(**);
     }

     # Only required if you use AsyncExecutor
     -keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent {
         (java.lang.Throwable);
     }

但这种处理方式,对于保密度要求高的程序而言也是不可接受的,因为这暴露了方法名,给逆向留下了口子。好消息是 EventBus 已经打算使用注解来实现,这应该能够解决代码混淆的问题。

 

 

3. 观察者

 观察者这种设计模式应当属于程序员的基本功,由于观察者的实现比较简单,因此性能上是三者中最好的,但观察者难以控制通知的优先度,特别是一开始没有考虑优先度中途更改需求又加入优先度。另外观察者模式要求观察者在事件发生时在场才能收到通知,这就使得观察者有可能遗漏事件,一般来说这并不是问题,但是当程序要求观察者不能遗漏事件时那就坑了。客观来说,这并不能算作观察者的缺点,因为其它的方式往往也是这样,更加严谨的说法是观察者没有 EventBus 优先级、粘滞事件的优点。但有一个缺点是观察者独有的,那就是观察者可能会造成接口的膨胀。特别是当程序要求大量形式各异的通知,而程序员有没有做出良好的抽象时,代码中会包含大量的接口,接口数量的增长又会带来命名、注释等等一大堆问题。本质上说观察者要求程序员从零开始实现事件的产生、分发与处理过程,这就要求参与者必须对整个通知过程有着良好的理解。当程序代码适量时,这是一个合理的要求,然而当程序太大时,这将成为一种负担。

你可能感兴趣的:(Android应用篇)