EventBus的高效使用

EventBus是我们开发中比较常用的一个中间件,这里基于3.1.1版本进行源码剖析。
使用EventBus的步骤:
1.添加库依赖,添加配置;

implementation 'org.greenrobot:eventbus:3.1.1'
// 给EventBus配置索引,提升效率 使用annotationProcessor 属性将EventBus批注处理器添加到构建中
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'   // 可选
  • 添加配置:(可选)
defaultConfig {
        ...

        javaCompileOptions {
            annotationProcessorOptions {
                // 设置参数 eventBusIndex以指定要生成的索引的完全限定类
                arguments = [ eventBusIndex : 'com.fly.kuanquan.EventBusIndex' ] // 这里要修改为你项目的包名
            }
        }
    }

2.初始化

  • 这里有个知识点,我们一般使用EventBus是这么写的:
EventBus.getDefault().register(this);

其实EventBus这个类的构造函数不是 private 而是 public,咋一看违背单例模式的写法,这是为什么呢?
原因就是,EventBus 可以创造出很多条总线来,不同的总线之间是不能传递事件的(不能通信)。
自定义创建EventBus:

EventBus eventBus = EventBus.builder()
                .logNoSubscriberMessages(false)
                .sendNoSubscriberEvent(false)
                .build();
        eventBus.register(this);

3.注销EventBus
这个没什么好说的就是把上面创建并注册好的EventBus注销掉

EventBus.getDefault().unregister(this);
// 或者
eventBus.unregister(this);

4.创建接收(订阅)事件的方法

@Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 4)
    public void onEventThread(EventCenter eventCenter){
        switch (eventCenter.getEventType()) {
        case EventType.ONE:
            Log.e("MainActivity", eventCenter.getEventType());
            break;

        default:
            break;
        }
//      EventBus.getDefault().removeStickyEvent(eventCenter);
//      EventBus.getDefault().cancelEventDelivery(eventCenter);
    }

PS:
这里面涉及到的知识点,@Subscribe注解

  • threadMode: 在EventBus中有四种线程模式
POSTING,  // EventBus 默认的线程模式 就是订阅的线程和发送事件的线程为同一线程
MAIN,  // 主线程,使用此模式的订阅必须快速返回,以避免阻塞主线程
MAIN_ORDERED, // 主线程,与 MAIN 不同,事件将始终排队等待传递。这样可以确保后调用不阻塞
ASYNC // 异步线程
  • sticky: sticky事件是事件订阅者(消费者)在事件发布之后再注册,依然能接收到该事件的特殊类型。详情我们在后面的源码中详细分析。

  • priority :优先级,默认为0,数值越大,优先级越高,越提前接收到事件。

如果在同一总线中,接受的线程模式为POSTING,这时候在优先级高的订阅者中接收并取消该事件,优先级底的就接收不到该事件了。

注:优先级不会影响具有不同ThreadModes的订阅者的传递顺序

  • 取消事件传递:
@Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 4)
    public void onEventThread(EventCenter eventCenter){
        switch (eventCenter.getEventType()) {
        case EventType.ONE:
            Log.e("MainActivity", eventCenter.getEventType());
            break;

        default:
            break;
        }
        // 取消事件传递 这里的参数是订阅的实体参数
        EventBus.getDefault().cancelEventDelivery(eventCenter); 
    }

注:当优先级更高的想取消事件传递时,只有当threadMode = ThreadMode.POSTING处于此状态才能取消事件传递有效。

5.发送事件

// 发送 sticky 事件,先发送后注册也能接受到该事件
EventBus.getDefault().postSticky(new EventCenter<>(EventType.ONE));
// 普通发送事件
EventBus.getDefault().post(new EventCenter<>(EventType.ONE));

以上都是最基本的用法,下面我们说一种可以提升效率的用法。
为什么说提升效率呢,因为EventBus3.0以后都是基于注解反射实现的,大家都知道反射是效率很低的,所以为了提高效率新增了一种办法,配置索引。

  • 使用annotationProcessor
    就是上面在app builde中添加脚本配置:
defaultConfig {
        .....

        javaCompileOptions {
            annotationProcessorOptions {
                // 设置参数 eventBusIndex以指定要生成的索引的完全限定类
                arguments = [ eventBusIndex : 'com.fly.kuanquan.EventBusIndex' ] // 这里要修改为你项目的包名
            }
        }
}

dependencies {
    .....

    // 给EventBus配置索引,提升效率 使用annotationProcessor 属性将EventBus批注处理器添加到构建中
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'

    // 配置完成后重新Rebuild Project项目,
    // 然后我们到\app\build\generated\source\apt\debug\package\查看是否生成所配置的的文件EventBusIndex
}

下面是我demo中app下的完整build.gladle,大家可做参考:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion '26.0.2'

    defaultConfig {
        applicationId "com.kuanquan.testdemo"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"

        javaCompileOptions {
            annotationProcessorOptions {
                // 设置参数 eventBusIndex以指定要生成的索引的完全限定类
                arguments = [ eventBusIndex : 'com.fly.kuanquan.EventBusIndex' ] // 这里要修改为你项目的包名
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support:design:25.0.1'
    compile 'com.android.support.constraint:constraint-layout:1.1.2'
    compile 'com.android.support:recyclerview-v7:25.+'
    compile 'com.google.code.gson:gson:2.8.2'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.squareup.retrofit2:retrofit:2.5.0'
    compile 'com.squareup.okhttp3:okhttp:3.12.1'
    //引入Gson支持
    compile 'com.squareup.retrofit2:converter-gson:2.0.1'

    // 给EventBus配置索引,提升效率 使用annotationProcessor 属性将EventBus批注处理器添加到构建中
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'

    // 配置完成后重新Rebuild Project项目,
    // 然后我们到\app\build\generated\source\apt\debug\package\查看是否生成所配置的的文件EventBusIndex
}

PS:

配置完成后重新Rebuild Project项目,然后我们到\app\build\generated\source\apt\debug\package\查看是否生成所配置的的文件EventBusIndex。EventBusIndex名称可随意自定义

通过注解生成的EventBusIndex

生成的索引:

package com.fly.kuanquan;

import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
import org.greenrobot.eventbus.meta.SubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;

import org.greenrobot.eventbus.ThreadMode;

import java.util.HashMap;
import java.util.Map;

/** This class is generated by EventBus, do not edit. */
public class EventBusIndex implements SubscriberInfoIndex {
    private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;

代码中设置了几种模式,这里就会生成几种
    static {
        SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(com.kuanquan.testdemo.FirstActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEventThreadActivity", com.kuanquan.testdemo.EventCenter.class,
                    ThreadMode.POSTING, 1, false),
        }));

        putIndex(new SimpleSubscriberInfo(com.kuanquan.testdemo.MainActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEventThread", com.kuanquan.testdemo.EventCenter.class, ThreadMode.MAIN),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

索引的使用:

  • 在Application中进行初始化
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
    }
}

接下来注册、注销、订阅方法、发送事件和上面一样一样的。

  • 注意:在第一次使用默认EventBus实例之前,这只能执行一次。对installDefaultEventBus()的后续调用 将引发异常。这可确保您的应用中的行为一致。所以应该在Application.class使用配置,和使用索引。

  • 当然索引可以创建多个:

EventBus eventBus = EventBus.builder()
                .addIndex(new EventBusAppIndex())
                .addIndex(new EventBusIndex()).build();

前提:你的应用程序有很多library和一个app组成,这样把上面的配置在每个library中配置一遍,就可以生成多个索引,然后把多个索引在Application中如上配置就好了。

代码混淆

-keepattributes *Annotation*
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
 
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    (java.lang.Throwable);
}

总结:

  • EventBus在一个订阅者类中只能注册一次。否则会抛出异常。
  • EventBus的Configuration配置和索引使用的时候注意installDefaultEventBus()只能调用一次。否则会抛出异常。
  • 当EventBus无法使用索引时,它将在运行时自动回退到反射。因此它仍然可以工作,只是有点慢。所以添加索引可以让EventBus的使用效率更高。
  • 事件的优先级中设置的值越大优先级越高,取消事件传递,必须是threadMode = ThreadMode.POSTING在这个情况下才能有效。
  • EventBus可以创建很多条总线的,总线与总线之间是不能通讯的。相互独立的。

最后附上官网的图:


官网图解EventBus

源码分析:https://www.jianshu.com/p/d521630da2c2
谢谢阅读,据说点赞的都是帅哥靓女!

你可能感兴趣的:(EventBus的高效使用)