基于Agera的EventBus实现库

96
zpayh
2016.11.08 12:03* 字数 1222

AgeraBus简介

AgeraBus 是基于谷歌开源的Agera实现的Android事件总线,实现了EventBus基本常用的功能,下面将为你一一介绍,如果要了解Agera,可以去看我文章后面推荐的两个地址。

添加依赖

在项目根目录的build.gradle中添加:

dependencies {
    compile 'xyz.zpayh:agerabus:1.0.4'
    compile 'com.google.android.agera:agera:1.3.0'
}

基本用法

一个事件总线的使用总是少不了订阅、取消、发送事件,还有获取数据,下面我们来看下AgeraBus的基本用法,首先我们定义一个普通的类充当一个事件类型:

public class User{

    private String mName;
    public User(String name){
        this.mName = name;
    }
    
    public void setName(String name){
        this.mName = name;
    }

    public String getName(){
        return this.mName;
    }
}

简单的订阅,注销事件以及获取最新数据:

public class BaseActivity extends Activity implements Updatable{

    ...

    @Override
    protected void onStart() {
        super.onStart();
        //register 同一个Updatable实例只能订阅同一种事件类型一次,如需重新
        //订阅,要先取消订阅,如果多次订阅会抛出异常,这里Activity实现了Updatable接口
        AgeraBus.getDefault()
                .addUpdatable(this,User.class);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // unregister 取消订阅时,这个Updatable实例必须已经订阅了此事件,
        // 如果取消没有订阅的Updatable,会抛出异常
        AgeraBus.getDefault()
                .removeUpdatable(this,User.class);
    }

    /**
     * 接收到事件时调用的接口
     * 
     */
    @Override
    public void update() {
        // accept
          AgeraBus.getDefault()//获取默认总线
                .getSupplier(User.class)//拿到数据提供者
                .get()//获取封装好的数据Result<User>
                .ifSucceededSendTo(new Receiver<User>() {//数据成功接收到就发送给接收者
                    @Override
                    public void accept(@NonNull User value) {
                        //打印吐司
                        Toast.makeText(BaseActivity.this, value.getName(), Toast.LENGTH_SHORT).show();
                    }
                });
    }
}

上面就是最基本的订阅、取消事件以及接收数据。至于发送事件的话,只有一个入口:

AgeraBus.getDefault().post(new User("Sherlock"));

上面就是AgeraBus最基本的用法,下面简单讲解一下,

Agera 使用 push event, pull data 模型(推送事件,拉取数据)。 push event:被观察者只做事件通知,不携带任何数据; pull data:观察者根据自己需要从数据仓库(Repository.get())拉取数据。

由于push event, pull data模型是数据和事件通知分离的,所以上面看到的Updatable接口设计上并没有携带数据过来的,我们在update方法里,如果要拉取数据,可以从AgeraBus拿到订阅事件的数据提供者:
Supplier,再从Supplier中获取数据。

进阶用法

EventBus 提供了线程分发,订阅优先级,取消事件分发,粘性事件,而这些在AgeraBus也都一一实现了。
使用这些高级功能时,我们的订阅方法是使用另外一个接口。下面会介绍到。

线程分发与线程模型

ThreadMode有四种:
PostThread,MainThread,BackgroundThread,Async.

  • PostThread 订阅者将会被调用在与发布线程同样的线程中。上面基本用法就是采取这样的线程分发的,不涉及线程切换,通常是四种模式开销最小的一个。对于简单任务来说这是推荐用法,但使用这个分发模型要小心不要在主线程执行耗时长的任务,避免阻塞主线程。
  • MainThread 订阅者将会被回调在Android的Main线程中,适用于更新UI而又不无法确定事件来源于哪个线程的情况。
  • BackgroundThread 订阅者将在后台线程被回调,如果发布线程本身不是主线程,那么行为就跟PostThread一致,如果是在主线程发布事件,会切换到后台线程执行。
  • Async 订阅者总是在一个单独的线程被回调。

订阅优先级

你可以在注册订阅者的时候设置优先级改变事件分发的顺序,按优先级从高到低分发事件回调。

取消事件分发

你可以在接收事件,拿到数据value之后中断之后的事件分发:

AgeraBus.getDefault().cancel(value);

value 是从Supplier拿到的事件的数据,在update中调用上面的取消分发,后续的订阅者将不会接收到此次事件。

粘性事件

Agera 的 push event, pull data模型天然就是支持粘性事件,它总会保存最近(最新)的值,这样订阅粘性事件总是可以拿到最近(如果有)的数据。

使用方法

要使用上面这些高级功能,我们用AgeraBus另外一个接口方法订阅事件:

    AgeraBus.getDefault()
                .compiler(User.class)//设置订阅事件的类型
                .priority(priority)//设置优先级,或者调用.noPriority()不设置优先级(即为默认0优先级)
                .sticky()//设置为接收粘性事件,或者调用.noSticky()设置为不接收粘性事件(默认不接收粘性事件)
                .background()//设置分发线程,有background(),main(),posting(),async()对应四个分发模式(默认为posting模式)
                .compile(updatable);//设置订阅者,完成订阅

订阅事件不要中断链式调用,最后一定要调用compile(Updatable)完成调用

基本用法中的:

    AgeraBus.getDefault()
                .addUpdatable(this,User.class);

就是全部设置了默认的方式(0优先级,不接收粘性事件,posting线程分发)。

注意

在不同线程分发时候拿到的数据,不一定是引发这次事件的数据,拿到的数据有可能要比引发事件的数据要新,在Agera Wiki 中文版中有说到,这是因为:

由于 push event, pull data 模型和多线程情况下,观察者可能看不到数据全部的更新记录。 这是特意设计的: 因为大多数情况下(尤其更新app UI), 本来就只需要关心最新的数据。

上面的使用方法可以参考我的这个项目地址 AgeraBus,里面有使用Demo。可以看下AgeraBus的具体实现,由于本人技术水平有限,如有Bug,欢迎讨论。

参考文章

zjutkz的要做一个有冒险精神的人!开启漫漫的agera之旅

Agera Wiki 中文版

Android
Web note ad 1