在这篇教程中,我会向您展现如何实现一个编译时注解处理的RxBus(事件总线)。
开始之前
由于本篇文章会比较长,先容许我申明一些问题。
本篇文章是建立在您对Java Annotation以及Annotation Process 熟悉的基础之上,且本篇文章不讨论那些在运行时(Runtime)通过反射获取注解实现的RxBus,只讨论在编译时(Compile)完成的注解处理。
如果您实在没有耐心看完本篇文章,您可以点击 Apollo 访问Github上的开源库直接阅读我的源码,截止于2016年8月9日02:00,Github上Apollo的版本为0.1.2。
注意!目前 Apollo 仍处于非稳定版本,0.2版本之前不建议用于生产环境。
本篇文章以下提及到的RxBus的实现统称Apollo。
Compile-time的好处
目前Android中的一些流行库,如Dagger2,ButterKnife等都使用了Compile-time的注解处理,在编译时生成注入代码,来实现注入功能。其实通过Java的反射机制,也可以实现同样的功能,而且实现更加简单方便,不过反射机制的性能是一个问题,大量使用反射,往往是APP严重性能问题的根本原因。
而编译时注解处理只会在编译的时候占用开发资源,生成额外的代码来实现功能,这些通过注解处理生成的Java源代码会同其他手写的源文件一同被编译进APK。
Apollo的实现
目前常用的EventBus,Otto都是基于观察者(发布/订阅)模式。
所以,对于RxJava来说,它也可以实现事件总线,因为它本生就是基于观察者模式的。
我们知道RxJava中Subject同时充当了Observer和Observable的角色,我们即可以通过Subject来发布事件,同时也可以通过Subject来接收事件。
在RxJava提供的几个Subject中,PublishSubject最符合目前所需。PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者
在编写代码前,我希望Apollo能够做到以下几点:事件都有Tag作为唯一标识,
订阅者只接收对应Tag的事件
事件可以是任何对象
支持sticky event功能(因为在事件发送的时候,可能订阅此事件的Activity还没有启动)
Apollo是单例的
在满足以上条件后,先开始编写不带注解功能的Apollo:
package com.lsxiao.apllo;
import com.lsxiao.apllo.annotations.Receive;
import com.lsxiao.apllo.entity.SubscriberEvent;
import com.lsxiao.apllo.entity.SubscriptionBinder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import rx.Observable;
import rx.Scheduler;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import rx.subjects.PublishSubject;
import rx.subjects.SerializedSubject;
/**
* author lsxiao
* date 2016-05-09 17:27
*/
public class Apollo {
private SerializedSubject mPublishSubject;
private final Map mStickyEventMap;//用于保存stick事件
private static Apollo sInstance;
private Apollo() {
//SerializedSubject是线程安全的
//PublishSubject 会发送订阅者从订阅之后的事件序列,这意味着没订阅前的事件序列不会被发送到当前订阅者
mPublishSubject = new SerializedSubject<>(PublishSubject.create());
mStickyEventMap = new ConcurrentHashMap<>();
mBindTargetMap = new HashMap<>();
}
/**
* 返回一个Apollo的单例对象
*
* @return Apollo
*/
public synchronized static Apollo get() {
if (null == sInstance) {
sInstance = new Apollo();
}
return sInstance;
}
/**
* 判断是否有订阅者
*/
public boolean hasObservers() {
return mPublishSubject.hasObservers();
}
/**
* 根据tag和eventType获取指定类型的Sticky事件
*/
public T getStickyEvent(String tag, Class eventType) {
synchronized (mStickyEventMap) {
Object o = mStickyEventMap.get(tag).getData();
if (o.getClass().getCanonicalName().equals(eventType.getCanonicalName())) {
return eventType.cast(o);
}
}
return null;
}
/**
* 根据tag获取Sticky事件
*/
public Object getStickyEvent(String tag) {
synchronized (mStickyEventMap) {
return mStickyEventMap.get(tag) == null ? null : mStickyEventMap.get(tag).getData();
}
}
/**
* 移除指定eventType的Sticky事件
*/
public void removeStickyEvent(String tag) {
synchronized (mStickyEventMap) {
mStickyEventMap.remove(tag);
}
}
/**
* 移除指定eventType的Sticky事件
*/
public void removeStickyEvent(String[] tags) {
for (String tag : tags) {
removeStickyEvent(tag);
}
}
/**
* 移除所有的Sticky事件
*/
public void removeAllStickyEvents() {
synchronized (mStickyEventMap) {
mStickyEventMap.clear();
}
}
/**
* 发送event
*
* @param event SubscriberEvent
*/
private void send(SubscriberEvent event) {
mPublishSubject.onNext(event);
}
/**
* 发送event
*
* @param tag Tag
* @param actual 内容
*/
public void send(String tag, Object actual) {
SubscriberEvent event = new SubscriberEvent(tag, actual);
send(event);
}
/**
* 发送只有tag的event
*
* @param tag Tag
*/
public void send(String tag) {
send(tag, new Object());
}
/**
* 发送一个新Sticky事件
*/
public void sendSticky(String tag, Object actual) {
synchronized (mStickyEventMap) {
SubscriberEvent event = new SubscriberEvent(tag, actual, true);
mStickyEventMap.put(tag, event);
send(event);
}
}
public void sendSticky(String tag) {
synchronized (mStickyEventMap) {
SubscriberEvent event = new SubscriberEvent(tag, new Object(), true);
mStickyEventMap.put(tag, event);
mPublishSubject.onNext(event);
}
}
public Observable toObservable(final String tag) {
return toObservable(new String[]{tag}, Object.class);
}
public Observable toObservable(final String[] tags) {
return toObservable(tags, Object.class);
}
/**
* 返回普通事件类型的被观察者
*
* @param eventType 只接受eventType类型的响应,ofType = filter + cast
* @return Observable
*/
public Observable toObservable(final String tag, final Class eventType) {
return toObservable(new String[]{tag}, eventType);
}
public Observable toObservable(final String[] tags, final Class eventType) {
if (null == eventType) {
throw new NullPointerException("the eventType must be not null");
}
if (null == tags) {
throw new NullPointerException("the tags must be not null");
}
if (0 == tags.length) {
throw new IllegalArgumentException("the tags must be not empty");
}
return mPublishSubject
.filter(new Func1() {
@Override
public Boolean call(SubscriberEvent subscriberEvent) {
return Arrays.asList(tags).contains(subscriberEvent.getTag()) &&
//如果subscriberEvent.getData() = null,不用再去检查是不是特定类型或者其子类的实例
(subscriberEvent.getData() == null || eventType.isInstance(subscriberEvent.getData()));
}
})
.flatMap(new Func1>() {
@Override
public Observable call(SubscriberEvent subscriberEvent) {
return Observable.just(eventType.cast(subscriberEvent.getData()));
}
});
}
public Observable toObservableSticky(final String tag) {
return toObservable(new String[]{tag});
}
public Observable toObservableSticky(final String[] tags) {
return toObservableSticky(tags, Object.class);
}
/**
* 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
*/
public Observable toObservableSticky(String tag, final Class eventType) {
return toObservableSticky(new String[]{tag}, eventType);
}
public Observable toObservableSticky(final String[] tags, final Class eventType) {
if (null == eventType) {
throw new NullPointerException("the eventType must be not null");
}
if (null == tags) {
throw new NullPointerException("the tags must be not null");
}
if (0 == tags.length) {
throw new IllegalArgumentException("the tags must be not empty");
}
synchronized (mStickyEventMap) {
//普通事件的被观察者
Observable observable = toObservable(tags, eventType);
final List stickyEventList = new ArrayList<>();
for (String tag : tags) {
//sticky事件
final SubscriberEvent event = mStickyEventMap.get(tag);
if (event != null) {
stickyEventList.add(mStickyEventMap.get(tag));
}
}
if (!stickyEventList.isEmpty()) {
//合并事件序列
return Observable.from(stickyEventList)
.flatMap(new Func1>() {
@Override
public Observable call(SubscriberEvent subscriberEvent) {
return Observable.just(eventType.cast(subscriberEvent.getData()));
}
}).mergeWith(observable);
} else {
return observable;
}
}
}
}上述代码中Subject同时充当了Observable以及Observer的功能,同时我们使用强制类型转换将PublishSubject转换成线程安全的SerializedSubject。
由于我们要实现通过tag接收event,以及sticky event功能,所以将tag和event封装成SubscriberEvent对象
我们在sendSticky()方法中将SubscriberEvent缓存起来,以便在有订阅者订阅sticky事件的时候,能够发送出去。
注意,toObservableSticky方法中对SubscriberEvent到源事件之间的转换,以及为了在接收到Sticky事件后还能继续接收普通事件,将普通的Observable和stickyObservable进行merge的操作。
思路分析
首先,创建一个同时可以充当Observable和Observer的Subject作为事件发布和订阅的桥梁。
在Acticity,Fragment等需要接收事件的类中实现订阅事件方法,例如:
Apollo.get().toObservable(User.class)
.subscribe(user -> {
//do something.
}, throwable -> {
throwable.printStackTrace();
}));
在我们需要发布事件的地方进行发布
Apollo.instance().send("SHOW_USER_INFO",user);
这样,在发布事件之前所有订阅了"SHOW_USER_INFO"普通事件的订阅者,都能够接收到"SHOW_USER_INFO"事件。
如果此事件发布之前订阅者还未订阅,我们可以发布一个Sticky事件:
Apollo.instance().sendSticky("SHOW_USER_INFO",user);
同时在订阅处通过toObservableSticky来订阅:
Apollo.get().toObservableSticky(User.class)
.subscribe(user -> {
//do something.
}, throwable -> {
throwable.printStackTrace();
}));
这样在订阅者订阅后,第一时间就会接收到此Sticky事件。注意,Sticky事件需要自行手动清除。
且注意在Activity/Fragment生命周期结束时候,一定要需要取消订阅,以防止RxJava引起的内存泄露。
@Override
protected void onDestroy() {
super.onDestroy();
if(!subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
}
上述代码已经实现了一个简单的RxBus。
基于编译时注解处理的Apollo实现
还记得上面的Apollo的功能要求吗?事件都有Tag作为唯一标识,
订阅者只接收对应Tag的事件
事件可以是任何对象
支持sticky event功能(因为在事件发送的时候,可能订阅此事件的Activity还没有启动)
Apollo是单例的
现在,我要在之前的基础在给Apollo增加一些新的功能
我现在想通过Annotation来简化订阅代码,实现订阅指定tag事件:
@Receive(tag ="SHOW_USER_INFO")
public void receiveUser(User user) {
Log.d("apollo", "receive user event" + user.toString());
}
通过Annotation控制接收事件的类型(sticky,normal)
@Receive(tag ="SHOW_USER_INFO",type=Receive.Type.STICKY)
public void receiveUser(User user) {
Log.d("apollo", "receive user event" + user.toString());
}
通过Annotation控制调度器
@Receive(tag ="SHOW_USER_INFO",
subscribeOn=Receive.Thread.IO,
observeOn=Receive.Thread.Main)
public void receiveUser(User user) {
Log.d("apollo", "receive user event" + user.toString());
}
通过以下的形式来进行绑定和解绑
public abstract class BaseActivity extends AppCompatActivity {
private SubscriptionBinder mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
afterCreate(savedInstanceState);
//绑定
mBinder = Apollo.get().bind(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//解绑
mBinder.unbind();
}
protected abstract int getLayoutId();
protected abstract void afterCreate(Bundle savedInstanceState);
}
由于开篇已经说过本篇文章只介绍如何实现Complie-time的Apollo,所以这里不考虑Run-time的反射机制实现。
在开始编写complie-time Apollo之前,我们先回顾一下Dagger2和ButterKnife,当使用的时候至少都需要引入两个module,其中有一个module一般叫做compiler或者processor(以下统称processor),例如:
compile 'com.jakewharton:butterknife:8.2.1'
apt 'com.jakewharton:butterknife-compiler:8.2.1'
processor的作用是负责完成注解处理,生成代码。
同时由于编译时用于生成代码的processor我们是不需要打包进apk的,所以使用apt而不是complie命令。
在这里,我把整个Apollo分成两个部分:一个是核心代码部分,实现主要的功能,提供绑定接口的apollo module。
一个是解析所有我们需要Annotation,生成指定绑定代码的processor module。
在编写processor之前,其实apollo的逻辑之前基本上已经完成的差不多了,这里主要需要实现的还剩:apollo提供绑定接口,让processor生成的绑定代码实现接口,初始化的时候让apollo持有生成 的绑定接口实现类实例。这样就可以在BaseActivity中通过apollo.get.bind()方式进行绑定。
apollo提供RxJava的基本调度器,而AndroidSchedulers.mainThread()在初始化的时候作为参数传入。(由于apollo module是一个java library,不能依赖作为Android library的RxAndroid,所以main调度器需要初始化的时候传入,之后我会提及到为什么apollo和processor都只能是java library)
这里先给出SubscriberBinder接口:
public interface SubscriberBinder {
SubscriptionBinder bind(Object object);
}
接口很简单,只需要实现一个bind方法,并且返回SubscriptionBinder对象(注意和SubscriberBinder的区别)。
SubscriberBinder的实现(用于取消订阅)
public class SubscriptionBinder {
private CompositeSubscription mSubscription;
public SubscriptionBinder() {
mSubscription = new CompositeSubscription();
}
public void add(Subscription subscription) {
if (mSubscription == null) {
throw new IllegalAccessError("this binder has been unbinded");
}
if (subscription == null) {
throw new NullPointerException("subscription must be not null");
}
mSubscription.add(subscription);
}
public void unbind() {
if (mSubscription != null && !mSubscription.isUnsubscribed()) {
mSubscription.unsubscribe();
mSubscription = null;
}
}
}
给Apollo添加绑定方法
public SubscriptionBinder bind(Object o) {
if (null == o) {
throw new NullPointerException("object to bind must not be null");
}
return mSubscriberBinder.bind(o);
}绑定成功后,返回一个SubscriptionBinder对象,在生命周期结束的时候我们可以调用SubscriptionBinder.unbind();方法来解绑当前Activity或者Fragment中所有的订阅者。
processor实现
在写processor之前,首先要知道AbstractProcessor这个抽象处理器,每一个注解处理器都必须继承此处理器(下面会有很多引用解释,不过不会赘述):
package com.example;
public class ApolloAnnotationProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment env){ }
@Override
public boolean process(Set extends TypeElement> annoations, RoundEnvironment env) { }
@Override
public Set getSupportedAnnotationTypes() { }
@Override
public SourceVersion getSupportedSourceVersion() { }
}init(ProcessingEnvironment env):-初始化操作的方法,RoundEnvironment会提供很多有用的工具类Elements、Types和Filer等
process(Set extends TypeElement> annoations, RoundEnvironment env):在这里进行注解的扫描,处理,Java代码的生成,是入口函数。注意!如果在此函数中,你生成了源代码,此process方法可能会被调用多次,因为你生成的源代码中可能也有会注解,process方法会继续对源代码文件进行处理,直至process中没有生成任何源文件。
getSupportedAnnotationTypes:返回需要处理的注解类型,也就是说注解处理器只处理那些注解,这里是必须指定的。
getSupportedSourceVersion():用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。在Java 7中,你也可以使用注解来代替getSupportedAnnotationTypes()和getSupportedSourceVersion(),像这样:
@SupportedSourceVersion(SourceVersion.latestSupported())
@SupportedAnnotationTypes({
// 合法注解全名的集合
})
public class MyProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment env){ }
@Override
public boolean process(Set extends TypeElement> annoations, RoundEnvironment env) { }
}
因为兼容的原因,特别是针对Android平台,我建议使用重载getSupportedAnnotationTypes()和getSupportedSourceVersion()方法代替@SupportedAnnotationTypes和@SupportedSourceVersion。注册处理器为了让自定义的Processor生效呢,需要在在processor的java同级目录新建resources/META-INF/services/javax.annotation.processing.Processor文件
- com
-lsxiao
-apollo
-processor
-ApolloAnnotationProcessor.java
- META-INF
- services
- javax.annotation.processing.Processor
然后在javax.annotation.processing.Processor文件中指定自定义的处理器,如:
com.lsxiao.apollo.processor.ApolloAnnotationProcessor
多个处理器换行写。
然后执行gradle build即可。
如果你在编译时注解处理中更高效率的开发,而不是用字符串拼接来生成源文件,就需要用到如下几个类库:Android Studio原本是不支持注解处理器的, 但是用android-apt这个插件后, 我们就可以使用注解处理器了,
这个插件可以自动的帮你为生成的代码创建目录, 让生成的代码编译到APK里面去, 而且它还可以让最终编译出来的APK里面不包含注解处理器本身的代码,因为这部分代码只是编译的时候需要用来生成代码, 最终运行的时候是不需要的。 也就是说它主要有两个目的:
允许配置只在编译时作为注解处理器的依赖,而不添加到最后的APK或library
设置源路径,使注解处理器生成的代码能被Android Studio正确的引用那在什么情况下我们会需要使用它呢?当你需要引入Processor生成的源代码到你的代码中时。例如当你使用Dagger 2或AndroidAnnotaition.
该插件使得Android Studio可以配置生成资源的build path,避免IDE报错。
当使用apt添加添加依赖,它将不会被包含到最终的APK里。
Google Auto的主要作用是注解Processor类,并对其生成META-INF的配置信息, 可以让你不用去写META-INF这些配置文件,只要在自定义的Processor上面加上@AutoService(Processor.class)javapoet:A Java API for generating .java source files.可以更方便的生成代码,它可以帮助我们通过类调用的形式来生成代码。
ApolloAnnotationProcessor.java
@AutoService(Processor.class)
public class ApolloAnnotationProcessor extends AbstractProcessor {
private ReceiveAnnotationHandler mReceiveAnnotationHandler;
//init():初始化操作的方法,RoundEnvironment会提供很多有用的工具类Elements、Types和Filer等。
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
Filer mFiler = processingEnv.getFiler();
Types mTypeUtil = processingEnv.getTypeUtils();
Elements mElementUtil = processingEnv.getElementUtils();
Messager mMessager = processingEnv.getMessager();
BaseHandler.init(mMessager, mTypeUtil, mElementUtil, mFiler);
mReceiveAnnotationHandler = new ReceiveAnnotationHandler();
}
//process()相当于每个处理器的主函数main()。在该方法中去扫描、评估、处理以及生成Java文件。
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
mReceiveAnnotationHandler.process(roundEnv);
return true;
}
/**
* 指定该注解处理器需要处理的注解类型
*
* @return 需要处理的注解类型名的集合Set
*/
@Override
public Set getSupportedAnnotationTypes() {
Set types = new HashSet<>();
types.add(com.lsxiao.apllo.annotations.Receive.class.getCanonicalName());
return types;
}
/**
* 指定使用的java版本。通常这里会直接放回SourceVersion.latestSupported()即可。
*
* @return SourceVersion
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
ReceiveAnnotationHandler.java(把process里面解析Receive的任务抽离出来,方便以后增加注解后的扩展)
public class ReceiveAnnotationHandler extends BaseHandler {
private Map> mClassMethodMap = new HashMap<>();
//如果生成了新的源文件process()能够被调用多次,因为生成的源文件中可能会有注解,它们还将会被ApolloAnnotationProcessor处理。
//所以这里需要是个是否完成标志变量,避免重复处理注解 创建源文件造成异常
private boolean handleComplete = false;
@Override
public void process(RoundEnvironment roundEnv) {
if (handleComplete) {
return;
}
//单例变量
FieldSpec.Builder fieldBuilder = FieldSpec.builder(Apollo.SubscriberBinder.class, "sInstance", Modifier.PRIVATE, Modifier.STATIC);
//单例方法
MethodSpec.Builder instanceMethodBuilder = MethodSpec.methodBuilder("instance")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.SYNCHRONIZED)
.returns(Apollo.SubscriberBinder.class)
.beginControlFlow("if (null == sInstance)")
.addStatement("sInstance = new SubscriberBinderImplement()")
.endControlFlow()
.addStatement("return sInstance");
//绑定方法
MethodSpec.Builder bindMethodBuilder = MethodSpec.methodBuilder("bind")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(SubscriptionBinder.class)
.addParameter(Object.class, "object")
.addStatement("final $T subscriptionBinder = new $T()", SubscriptionBinder.class, SubscriptionBinder.class);
for (Element element : roundEnv.getElementsAnnotatedWith(Receive.class)) {
//注解最最外侧必须是一个类
if (element.getEnclosingElement().getKind() != ElementKind.CLASS) {
//打印出错信息
error("@Receive must be wrapped by a class");
}
if (element.getKind() != ElementKind.METHOD) {
error("@Receive only support method!");
}
//转行成可执行element
ExecutableElement receiveMethodElement = (ExecutableElement) element;
//找到注解所属的类
TypeElement classElementAnnotationIn = (TypeElement) element.getEnclosingElement();
//获取类的完全限定名
final DeclaredType declaredType = getTypeUtil().getDeclaredType(classElementAnnotationIn);
List methodList = mClassMethodMap.get(declaredType);
if (methodList == null) {
methodList = new ArrayList<>();
mClassMethodMap.put(declaredType, methodList);
}
//存储方法
methodList.add(receiveMethodElement);
}
for (DeclaredType classTypeAnnotationIn : mClassMethodMap.keySet()) {
String receiveMethodInvoker = StrUtil.dot2Underline(classTypeAnnotationIn.toString());
bindMethodBuilder
.beginControlFlow("if(object.getClass().getCanonicalName().equals($S))", classTypeAnnotationIn.toString())
.addStatement("final $T $N=($T)object", classTypeAnnotationIn, receiveMethodInvoker, classTypeAnnotationIn);
for (ExecutableElement methodElement : mClassMethodMap.get(classTypeAnnotationIn)) {
//receive方法只能有一个变量
if (methodElement.getParameters().size() > 1) {
error("the " + methodElement.toString() + " method in " + classTypeAnnotationIn.toString() + " only support 1 parameter,but there are " + methodElement.getParameters().size());
}
//获取方法第一个变量
VariableElement eventVariable = methodElement.getParameters().get(0);
//获取tag值
String tag = methodElement.getAnnotation(Receive.class).tag();
Receive.Thread observeOn = methodElement.getAnnotation(Receive.class).observeOn();
Receive.Thread subscribeOn = methodElement.getAnnotation(Receive.class).subscribeOn();
//获取receiveMethod是否接收sticky event
boolean isSticky = methodElement.getAnnotation(Receive.class).type() == Receive.Type.STICKY;
String receiveMethod = methodElement.getSimpleName().toString();
String onSubscribeMethod = isSticky ? "toObservableSticky" : "toObservable";
String eventVariableClassType = eventVariable.asType().toString() + ".class";
String eventVariableClass = eventVariable.asType().toString();
String eventVariableInstance = eventVariable.getSimpleName().toString().toLowerCase();
bindMethodBuilder
.addStatement("subscriptionBinder.add($T.get().$N($S,$N).subscribeOn($T.get().getThread().get($N.$N)).observeOn($T.get().getThread().get($N.$N)).subscribe(" +
"new $T(){" +
"@Override " +
"public void call($N $N){" +
"$N.$N($N);" +
"}}," +
"new $T(){" +
"@Override " +
"public void call($T a){" +
"a.printStackTrace();" +
"}}" +
"))",
Apollo.class,
onSubscribeMethod,
tag,
eventVariableClassType,
Apollo.class,
Receive.Thread.class.getCanonicalName(),
subscribeOn.name(),
Apollo.class,
Receive.Thread.class.getCanonicalName(),
observeOn.name(),
Action1.class,
eventVariableClass,
eventVariableClass,
eventVariableInstance,
receiveMethodInvoker,
receiveMethod,
eventVariableInstance,
Action1.class,
Throwable.class,
Throwable.class);
}
bindMethodBuilder.endControlFlow();
}
bindMethodBuilder.addStatement("return subscriptionBinder");
TypeSpec subscriberClass = TypeSpec.classBuilder("SubscriberBinderImplement")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addSuperinterface(Apollo.SubscriberBinder.class)
.addField(fieldBuilder.build())
.addMethod(instanceMethodBuilder.build())
.addMethod(bindMethodBuilder.build())
.build();
generateCode(subscriberClass);
}
private void generateCode(TypeSpec subscriberClass) {
JavaFile javaFile = JavaFile.builder("com.lsxiao.apollo.generate", subscriberClass)
.build();
try {
javaFile.writeTo(getFiler());
handleComplete = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}上面的代码使用Javapoet完成了一个SubscriberBinder接口的实现类,提供了静态方法能够获取SubscriberBinderImplement单例。
被注解的方法只能接收一个事件参数
被注解的方法最外侧结点必须是一个类
根据注解的tag,type,以及thread分别为对应的方法订阅对应的tag事件,并且在输出的时候讲事件转换成发送时候的类型,最后在subscribeOn和observeO指定线程调度器。
最后demo中生成的源文件如下
public final class SubscriberBinderImplement implements Apollo.SubscriberBinder {
private static Apollo.SubscriberBinder sInstance;
public static synchronized Apollo.SubscriberBinder instance() {
if (null == sInstance) {
sInstance = new SubscriberBinderImplement();
}
return sInstance;
}
@Override
public SubscriptionBinder bind(Object object) {
final SubscriptionBinder subscriptionBinder = new SubscriptionBinder();
if (object.getClass().getCanonicalName().equals("com.lsxiao.apollo.demo.activity.MainActivity")) {
final MainActivity com_lsxiao_apollo_demo_activity_MainActivity = (MainActivity) object;
subscriptionBinder.add(Apollo.get().toObservable("event_show_book", com.lsxiao.apollo.demo.activity.MainActivity.Book.class).subscribeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.IO)).observeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.MAIN)).subscribe(new Action1() {
@Override
public void call(com.lsxiao.apollo.demo.activity.MainActivity.Book book) {
com_lsxiao_apollo_demo_activity_MainActivity.receiveBook(book);
}
}, new Action1() {
@Override
public void call(Throwable a) {
a.printStackTrace();
}
}));
subscriptionBinder.add(Apollo.get().toObservable("event_show_user", com.lsxiao.apollo.demo.activity.MainActivity.User.class).subscribeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.IO)).observeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.MAIN)).subscribe(new Action1() {
@Override
public void call(com.lsxiao.apollo.demo.activity.MainActivity.User user) {
com_lsxiao_apollo_demo_activity_MainActivity.receiveUser(user);
}
}, new Action1() {
@Override
public void call(Throwable a) {
a.printStackTrace();
}
}));
}
if (object.getClass().getCanonicalName().equals("com.lsxiao.apollo.demo.activity.BookActivity")) {
final BookActivity com_lsxiao_apollo_demo_activity_BookActivity = (BookActivity) object;
subscriptionBinder.add(Apollo.get().toObservableSticky("event_show_book", com.lsxiao.apollo.demo.activity.MainActivity.Book.class).subscribeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.IO)).observeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.MAIN)).subscribe(new Action1() {
@Override
public void call(com.lsxiao.apollo.demo.activity.MainActivity.Book book) {
com_lsxiao_apollo_demo_activity_BookActivity.receiveBook(book);
}
}, new Action1() {
@Override
public void call(Throwable a) {
a.printStackTrace();
}
}));
}
return subscriptionBinder;
}
}
初始化
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
Apollo.get().init(SubscriberBinderImplement.instance(), AndroidSchedulers.mainThread());
}
}以上就是整个Complie-time RxBus的整体实现,详细细节可以查看Apollo。
ps.注意!再次提醒目前 Apollo 仍处于非稳定版本,0.2版本之前不建议用于生产环境。