EventBus: Android 组件间通讯的高效方式

来源:互联网 发布:中宣部是阎王殿知乎 编辑:程序博客网 时间:2024/05/09 23:21

最近,以EventBus 作为Android 组件间的通讯方式比较流行,在github上找到了EventBus的项目源码及其相关介绍,在此将其中关键部文翻译为中文,并加入一些个人的理解。
EventBus 项目链接:https://github.com/greenrobot/EventBus

EventBus 是一个Android 端优化 的 publish/subscribe 消息总线

EventBus框架图

EventBus 优势

  • 简化组件间的通讯
  • 简化代码,使代码更优雅,更易管理
  • 速度快
  • 容量小(<50k jar)
  • 实践证明已有一亿个应用集成EventBus
  • 拥有先进的功能,如交付线程、订阅者优先级等

EventBus使用步聚三部走

1.定义事件
EventsBus对事件没有任何特殊的要求

public class MessageEvent {    public final String message;    public MessageEvent(String message) {        this.message = message;    }}

2.准备订阅者
订阅者需要实现onEventXXX方法,这个方法会在事件到时被调用。订阅者需要将自己注册到EventBus 中去,在适当的地方解除注册。

    @Override    public void onStart() {        super.onStart();        EventBus.getDefault().register(this);    }    @Override    public void onStop() {        EventBus.getDefault().unregister(this);        super.onStop();    }//这个方法将在MessageEvent 被 post 之后调用;    public void onEvent(MessageEvent event){        Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();    }    //这个方法将在SomeOtherEvent  被 post 之后调用;    public void onEvent(SomeOtherEvent event){        doSomethingWith(event);    }

3.发布事件

可以从代码的任何地方 post(发布)一个事件,所有拥有和这个事件类型匹配的onEventXXX()方法的订阅者都会收到这个事件(消息)

EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

线程切换和线程模式

EventBus 可以处理线程切换问题,事件可以在任何线程中被发布,也可以在任何线程中被处理。
一个普遍的应用是用于更新UI。在Android 中,更新UI必须在主线程中完成,请求网络等耗时操作不能在主线程中执行,否则在造成界面卡顿阻塞。EventBus 可以轻松地解决这个任务,与UI线程中实现同步(不再需要专注于线程转换,使用AsyncTask,使代码更加简化,更易于管理 );

在EventBus中,可以控制事件处理方法onEventXXX中的代码在哪种线程中执行, 通过使用EventBus中的线程模式可以实现这一点

Subscriber函数的名字只能是4个(onEvent、onEventMainThread、onEventBackgroundThread、onEventAsync),因为每个事件订阅函数都是和一个`ThreadMode相关联的,ThreadMode指定了会调用的函数。有以下四个ThreadMode:

  • PostThread(发布线程):

事件的处理在和事件的发送在相同的进程,所以事件处理时间不应太长,不然影响事件的发送线程,而这个线程可能是UI线程。对应的函数名是onEvent。

  // Called in Android UI's main thread    public void onEventMainThread(MessageEvent event) {        textField.setText(event.message);    }
  • MainThread(主线程):

事件的处理会在UI线程中执行。事件处理时间不能太长,这个不用说的,长了会ANR的,对应的函数名是onEventMainThread。

 // Called in Android UI's main thread    public void onEventMainThread(MessageEvent event) {        textField.setText(event.message);    }
  • BackgroundThread(后台线程):

事件的处理会在一个后台线程中执行,对应的函数名是onEventBackgroundThread,虽然名字是BackgroundThread,事件处理是在后台线程,但事件处理时间还是不应该太长,因为如果发送事件的线程是后台线程,会直接执行事件,如果当前线程是UI线程,事件会被加到一个队列中,由一个线程依次处理这些事件,如果某个事件处理时间太长,会阻塞后面的事件的派发或处理。

 // Called in the background thread    public void onEventBackgroundThread(MessageEvent event){        saveToDisk(event.message);
  • Async(异步线程):

事件处理会在单独的线程中执行,主要用于在后台线程中执行耗时操作,每个事件会开启一个线程(EventBus有线程池作管理),但最好限制线程的数目

// Called in a separate thread    public void onEventAsync(MessageEvent event){        backend.send(event.message);    }

订阅者优先级(Android 广播机制中也有优先级的概念)
在注册订阅者时,可以为订阅者指定优先级,当事件被 post时,处在同一线程模式(ThreadMode)且优先级高的订阅者将先收到这个事件。EventBus 中,默认的优先级是0;

int priority = 1;    EventBus.getDefault().register(this, priority);

取消事件传递(类似广播拦截)
可以在订阅者事件处理方法中,通过调用cancelEventDelivery(Object event),取消事件的传递。后继的订阅者将不会接收到这个事件

 // Called in the same thread (default)    public void onEvent(MessageEvent event){        // Process the event         ...        EventBus.getDefault().cancelEventDelivery(event) ;    }

事件经常是被 优先级较高的订阅者取消继续传递。有一点需要注意,`这个事件的ThreadMode必须是PostThread,并且只能终止它在处理的事件。

Sticky Event (棘手事件?粘性事件?暂且不纠结如何翻译,说说它的应用场景)

当被发布的某些事件中携带着感兴趣的信息。例如,一件事件发送一个某些初始化已经完成的信号。假设你想保存某些传感器或者地理信息的最新数据,你并不需要自己去实现缓存,可以使用sticky events. EventBus 可以在内存中保存最后一个post的sticky 事件。sticky 事件同样可以传递到订阅者那里去,还可以被准确查询(最后一个post 的sticky event)

假设下面是一个在一段时间之前post 的一个sticky event:

EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));

然后,一个新的Activity启动。当使用registerSicky注册时,将后立马收到一个最新的sticky event

  @Override    public void onStart() {        super.onStart();        EventBus.getDefault().registerSticky(this);    }    public void onEventMainThread(MessageEvent event) {        textField.setText(event.message);    }    @Override    public void onStop() {        EventBus.getDefault().unregister(this);        super.onStop();    }

不通过注册,也可以得到一个特定类型的最后一个sticky event

 EventBus.getDefault().getStickyEvent(Class<?> eventType)

始终得记住的一点就是:EventBus 只缓存特定类型的最后一个的sticky event

EventBus其它特性:

  • 并非基于注解:在Android中注解的查询比较慢,尤其是在Android4.0以下版本
  • 基于约定:事件处理方法以“onEventXXX”命名
  • 性能优秀:它可能是Android中最快的消息通讯机制
  • 方便的单例:调用EventBus.getDefault()可以获取EventBus的实例。你也可以用 new 的方式创建另一辆消息列车
  • 订阅者和事件的继承:事件处理方法可以定义在订阅者的父类中,事件的类型也可以用事件的父类声明。

EventBus 缺点:

无法进程间通信,如果一个应用内有多个进程的话就没办法了

注意事项

  1. 同一个onEvent函数不能被注册两次,所以不能在一个类中注册同时还在父类中注册
  2. 当Post一个事件时,这个事件类的父类的事件也会被Post。
  3. Post的事件无Subscriber处理时会Post NoSubscriberEvent事件, 当调用Subscriber 中 onEventXXX 失败时会Post SubscriberExceptionEvent`事件。
0 0
原创粉丝点击