Apollo-基于编译时注解处理的RxBus实现

Apollo-基于编译时注解处理的RxBus实现

LisonLison

在这篇教程中,我会向您展现如何实现一个编译时注解处理的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能够做到以下几点:

  1. 事件都有Tag作为唯一标识,
  2. 订阅者只接收对应Tag的事件
  3. 事件可以是任何对象
  4. 支持sticky event功能(因为在事件发送的时候,可能订阅此事件的Activity还没有启动)
  5. 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<SubscriberEvent, SubscriberEvent> mPublishSubject;
    private final Map<String, SubscriberEvent> mStickyEventMap;//用于保存stick事件
    private static Apollo sInstance;

    private Apollo() {
        //SerializedSubject是线程安全的
        //PublishSubject 会发送订阅者从订阅之后的事件序列,这意味着没订阅前的事件序列不会被发送到当前订阅者
        mPublishSubject = new SerializedSubject<>(PublishSubject.<SubscriberEvent>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> T getStickyEvent(String tag, Class<T> 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<Object> toObservable(final String tag) {
        return toObservable(new String[]{tag}, Object.class);
    }

    public Observable<Object> toObservable(final String[] tags) {
        return toObservable(tags, Object.class);
    }

    /**
     * 返回普通事件类型的被观察者
     *
     * @param eventType 只接受eventType类型的响应,ofType = filter + cast
     * @return Observable
     */
    public <T> Observable<T> toObservable(final String tag, final Class<T> eventType) {
        return toObservable(new String[]{tag}, eventType);
    }

    public <T> Observable<T> toObservable(final String[] tags, final Class<T> 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<SubscriberEvent, Boolean>() {
                    @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<SubscriberEvent, Observable<T>>() {
                    @Override
                    public Observable<T> call(SubscriberEvent subscriberEvent) {
                        return Observable.just(eventType.cast(subscriberEvent.getData()));
                    }
                });
    }

    public Observable toObservableSticky(final String tag) {
        return toObservable(new String[]{tag});
    }

    public Observable<Object> toObservableSticky(final String[] tags) {
        return toObservableSticky(tags, Object.class);
    }


    /**
     * 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
     */
    public <T> Observable<T> toObservableSticky(String tag, final Class<T> eventType) {
        return toObservableSticky(new String[]{tag}, eventType);
    }

    public <T> Observable<T> toObservableSticky(final String[] tags, final Class<T> 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<T> observable = toObservable(tags, eventType);

            final List<SubscriberEvent> 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<SubscriberEvent, Observable<T>>() {
                            @Override
                            public Observable<T> 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的功能要求吗?

  1. 事件都有Tag作为唯一标识,
  2. 订阅者只接收对应Tag的事件
  3. 事件可以是任何对象
  4. 支持sticky event功能(因为在事件发送的时候,可能订阅此事件的Activity还没有启动)
  5. Apollo是单例的

现在,我要在之前的基础在给Apollo增加一些新的功能


  1. 我现在想通过Annotation来简化订阅代码,实现订阅指定tag事件:
  2. @Receive(tag ="SHOW_USER_INFO")
    public void receiveUser(User user) {
        Log.d("apollo", "receive user event" + user.toString());
    }
    
  3. 通过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());
    }
    
  4. 通过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());
    }
    
  5. 通过以下的形式来进行绑定和解绑
    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<String> 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<String>
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> 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<DeclaredType, List<ExecutableElement>> 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<ExecutableElement> 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<$N>(){" +
"@Override " +
"public void call($N $N){" +
"$N.$N($N);" +
"}}," +
"new $T<$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<com.lsxiao.apollo.demo.activity.MainActivity.Book>() {
@Override
                public void call(com.lsxiao.apollo.demo.activity.MainActivity.Book book) {
com_lsxiao_apollo_demo_activity_MainActivity.receiveBook(book);
                }
            }, new Action1<Throwable>() {
@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<com.lsxiao.apollo.demo.activity.MainActivity.User>() {
@Override
                public void call(com.lsxiao.apollo.demo.activity.MainActivity.User user) {
com_lsxiao_apollo_demo_activity_MainActivity.receiveUser(user);
                }
            }, new Action1<Throwable>() {
@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<com.lsxiao.apollo.demo.activity.MainActivity.Book>() {
@Override
                public void call(com.lsxiao.apollo.demo.activity.MainActivity.Book book) {
com_lsxiao_apollo_demo_activity_BookActivity.receiveBook(book);
                }
            }, new Action1<Throwable>() {
@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版本之前不建议用于生产环境。

文章被以下专栏收录
5 条评论
推荐阅读