Android 组件间的解耦

来源:互联网 发布:java泛型的通配符 编辑:程序博客网 时间:2024/06/06 14:01

EventBus、Otto, Android 自身提供的BroadcastReceiver/Intent System 和利用Handler实现的类似广播功能
用来简化应用组件间的通信。

对比主要如下:

 Otto

主要使用Bus类和两个注解@Produce, @Subscribe注解。
@Subscribe 注解告诉Bus该函数订阅了一个事件,该事件的类型为该函数的参数类型;
@Produce 注解告诉Bus该函数是一个事件产生者,产生的事件类型为该函数的返回值。

 EventBus

Event Bus 与 Otto 相比,主要有3点不同:
1.事件的订阅不是基于注解(Annotation)的,而是基于命名约定的。
在Android 4.0之前的版本中,注解解析起来比较慢,事件响应函数默认以“onEvent”开始,可以在EventBus中修改这个值,但是不推荐这么干。


2.事件响应有更多的线程选择。

Otto默认就是在Main线程中执行。

EventBus可以向不同的线程中发布事件,在ThreadMode枚举中定义了4个线程,只需要在事件响应函数名称"onEvent"后面添加对应的线程类型名称,则事件响应函数就会在对应的线程中执行。
比如事件函数"onEventAsync"就会在另外一个异步线程中执行。
四种线程类型如下:
1.PostThread: 事件响应函数和事件发布在同一个线程中执行。这个是默认值,这样可以避免线程切换而带来的消耗。
2.MainThread: 事件响应函数会在Android应用的主线程(UI线程)中执行。
3.BackgroundThread: 事件响应函数会在一个后台线程中执行。如果事件发布函数不是在主线程中,而会立即在事件发布线程中执行响应函数。但如果事件发布函数在主线程中,EventBus则会在唯一的一个后台线程中按顺序来执行所有的后台事件响应函数。
4.Async: 事件响应函数在另外一个异步线程中执行。该线程和发布线程、主线程相互独立。如果事件响应函数需要较长的时间执行,则应该使用该模式,例如网络访问等。

需要注意的是,由于系统并行的限制,应该避免在同一时间触发大量的异步线程。EventBus使用一个线程池来提高线程的效率。


3.EventBus 支持Sticky Event
有时候某个事件可能会用到多次,可以把该事件发布为Sticky Event,然后,当需要查询该信息的时候,可以通过Bus的getStickyEvent(ClassEventType)函数来查询最新发布的Event对象。
同一类型的事件只保存最新的Event对象。
注册和发布事件的函数分别为registerSticky() 和 postSticky()。

EventBus 可以解决大多数的需求,但是有没有这样一种需求??  我需要通知界面进行更新,但目前所在的界面又不需要进行更新,可不可以像这样去更新:如果当前界面需要更新,则通知当前界面进行更新,否则不更新;通知界面需要更新的,如果待更新界面不在前台,则不更新,待其被切换到前台再进行检查是否需要更新,即延迟更新。

3 利用Handler实现类似广播的功能。

相对比较灵活,不管是在UI线程或者后台线程, 都可以通过Handler发送Message 通知相应的接受者进行相应的处理,也是一个不错的选择。

不足之处:
1) 一旦有增加或者删除相应的事件,都要去修改类似消息定义配置类文件中的MSGID了。 经常改动
优点:
相对EventBus或Otto 不可以发送延迟事件, 但Handler可以post delay消息。

4 BroadcastReceiver/Intent System 

优点:

利用Android的自带的广播机制,不用像Otto, EventBus 或者Handler 专门去为了实现而写大量东西,减少了开发成本;

缺点:
1)必须register/unregister, 否则会出现内存泄漏
2)耗时操作必须与service一起使用,否则ANR.

PS:Annotation注解

1.作用:
1)编译期间检查
Annotation具有“让编译器进行编译检查的作用”。
例如:@SuppressWarnings, @Deprecated和@Override都具有编译检查作用。

2)在反射中使用Annotation
在反射的Class,Method, Field等函数中,有许多Annotation相关的接口。这也意味着,可以在反射中解析并使用Annotation。

2. 组成部分:
每一个Annotation都与1个RetentionPolicy关联,并且与“1~n个ElementType”关联。可以通俗的理解为:
每1个Annotaion对象,都会有唯一的RetentionPolicy属性;至于ElementType属性,则有1~n个。
public enum ElementType {    TYPE,               /* 类、接口(包括注释类型)或枚举声明  */    FIELD,              /* 字段声明(包括枚举常量)  */    METHOD,             /* 方法声明  */    PARAMETER,          /* 参数声明  */    CONSTRUCTOR,        /* 构造方法声明  */    LOCAL_VARIABLE,     /* 局部变量声明  */    ANNOTATION_TYPE,    /* 注释类型声明  */    PACKAGE             /* 包声明  */}

public enum RetentionPolicy {    SOURCE,            /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */    CLASS,             /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */    RUNTIME            /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */}

2. Annotation 通用定义
@Documented@Target(ElementType.Type)@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation1 {}
其中:
@interface 意味着它实现了java.lang.annotation.Annotation接口,即该注解就是一个Annotation。
定义Annotation时,@interface是必须的。 

@Documented
类和方法的Annotaion在缺省情况下是不出现在javadoc中的,如果使用@Documented修饰该Annotation,则表示它可以出现在javadoc中。
定义Annotation时,@Documented可有可无;若没有定义,则Annotation不会出现在javadoc中。

@Target(ElementType.TYPE)
ElementType是Annotation的类型属性。而@Target的作用,就是用来指定Annotation的类型属性。
定义Annotation时,@Target可有可无。若有@Target,则该Annotation只能用于它所指定的地方;若没有@Target,则该Annotation可以用于任何地方。

@Retention(RetentionPolicy.RUNTIME)
RetentionPolicy 是Annotation的策略属性,而@Retention的作用,就是指定Annotation的策略属性。
定义Annotation时,@Retention可有可无。若没有@Retention,则默认是RetentionPolicy.CLASS。
0 0