In this tutorial, I show you how to implement an RxBus(event Bus) for compile-time annotation handling.

Prior to the start

Since this article is going to be a long one, allow me to state some issues.

This article builds on your familiarity with Java annotations and the Annotation Process, and this article does not discuss RxBus, which is implemented by reflection to get annotations at Runtime, but only Annotation processing that is completed at Compile time.

If you don’t have the patience to finish this article, you can click on Apollo to visit the Github open source library and read my source code directly. As of 02:00, August 9, 2016, Apollo is available at Github version 0.1.2.

Attention! Apollo is still in unstable release and is not recommended for production before version 0.2.

The implementation of RxBus referred to below in this article is collectively called Apollo.

The benefits of the Compile – time

At present, some popular libraries in Android, such as Dagger2 and ButterKnife, use compile-time annotation processing to generate injection code at Compile time to achieve injection function. In fact, Java reflection mechanism can also achieve the same function, and the implementation is simpler and more convenient, but the performance of reflection mechanism is a problem, and the extensive use of reflection is often the root cause of APP serious performance problems.

Compile-time annotation processing, on the other hand, takes up development resources at compile time and generates additional code to implement the functionality. This Java source code generated through annotation processing is compiled into APK along with other handwritten source files.


ApolloThe implementation of the

Currently, EventBus,Otto, is based on the observer (publish/subscribe) model.

So, for RxJava, it can also implement the event bus because it is born based on the observer pattern.

We know that in RxJava, Subject acts as both an Observer and an Observable. We can publish events through Subject and receive events through Subject.

Of the several subjects that RxJava provides, PublishSubject is the one that best fits the current requirements.

The PublishSubject only emits data from the original Observable to the observer after the point in time the subscription occurred


Before writing the code, I wanted Apollo to do the following:

  1. Events are uniquely identified by tags,
  2. Subscribers only receive events corresponding to tags
  3. An event can be any object
  4. Support for sticky Event functionality (because the Activity that might subscribe to the event has not been started at the time the event is sent)
  5. Apollo is singleton

After the above conditions are met, start writing Apollo without annotations:

public class Apollo { private Subject mPublishSubject; private final Map mStickyEventMap; Private static Apollo sInstance; Private Apollo() {//SerializedSubject is thread-safe // /PublishSubject will send a sequence of events since the subscriber subscribed, meaning that the sequence of events before the subscription is not sent to the current subscriber mPublishSubject = new SerializedSubject<>(PublishSubject.create()); mStickyEventMap = new ConcurrentHashMap<>(); Public synchronized static Apollo get() {if (null == sInstance) {public synchronized static Apollo get() { sInstance = new Apollo(); } return sInstance; } / judge whether have the subscriber * * * * / public Boolean hasObservers () {return mPublishSubject. HasObservers (); } /** * 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; } public Object getStickyEvent(String tag) {synchronized (mStickyEventMap) {return mStickyEventMap.get(tag) == null ? null : mStickyEventMap.get(tag).getData(); Public void removeStickyEvent(String tag) {synchronized (mStickyEventMap) {synchronized (mStickyEventMap) { mStickyEventMap.remove(tag); } /** * removeAllStickyEvents */ public void removeAllStickyEvents() {synchronized (mStickyEventMap) { mStickyEventMap.clear(); }} /** * Send normal event ** @param tag @param O event */ public void send(String tag, Object o) { SubscriberEvent event = new SubscriberEvent(tag, o); mPublishSubject.onNext(event); } /** * send a Sticky event */ public void sendSticky(String tag, Object o) { synchronized (mStickyEventMap) { SubscriberEvent event = new SubscriberEvent(tag, o, true); mStickyEventMap.put(tag, event); mPublishSubject.onNext(event); @param eventType accepts only eventType responses. OfType = filter + cast * @return Observable */ public Observable toObservable(final String tag, Class eventType) { return mPublishSubject.filter(new Func1() { @Override public Object call(Object o) { return ((SubscriberEvent) o).getTag().equals(tag); } }).map(new Func1() { @Override public Object call(Object o) { return ((SubscriberEvent) o).getData(); } }).ofType(eventType); Public Observable toObservableSticky public Observable toObservableSticky public Observable toObservableSticky public Observable toObservableSticky Final Class eventType) {synchronized (mStickyEventMap) {// Observable Observable = toObservable(tag, synchronized) eventType); // StickyEvent Final SubscriberEvent event = mstickyeventmap.get (tag); if (event ! Return Observable.create(new Observable.OnSubscribe() {@override public void call(Subscriber super) SubscriberEvent> subscriber) { subscriber.onNext(event); } }).flatMap(new Func1>() { @Override public Observable call(SubscriberEvent subscriberEvent) { return Observable.just(eventType.cast(subscriberEvent.getData())); } }).mergeWith(observable); } else { return observable; Public class SubscriberEvent {private final String tag; private final Object data; private final Boolean sticky; public SubscriberEvent(String tag, Object data, boolean sticky) { this.tag = tag; this.data = data; this.sticky = sticky; } public SubscriberEvent(String tag, Object data) { this(tag, data, false); } public Object getData() { return data; } public String getTag() { return tag; } public Boolean isSticky() { return sticky; }}}Copy the code

  • In the above code, Subject acts as both an Observable and an Observer, and we use cast to convert the PublishSubject to a thread-safe SerializedSubject.
  • Since we want to implement receiving events through tags and sticky Events, we encapsulate the Tags and events into SubscriberEvent objects
  • We cache the SubscriberEvent in the sendSticky() method so that it can be sent when a subscriber subscribes to the sticky event.
  • Note that toObservableSticky converts subscriberEvents to source events and merges common Observables and stickyObservables in order to continue receiving common events after receiving Sticky events.

Thought analysis

First, create a bridge between event publishing and subscribing to a Subject that acts as both an Observable and Observer.

Implement subscription event methods in classes that need to accept events, such as AcElasticity,Fragment, etc., for example:

Apollo.get().toObservable(User.class)
                .subscribe(user -> {
                    //do something.
                }, throwable -> {
                    throwable.printStackTrace();
                }));
Copy the code

Publish where we need to publish events

Apollo.instance().send("SHOW_USER_INFO",user);
Copy the code


In this way, all subscribers who subscribed to the “SHOW_USER_INFO” normal event will receive the “SHOW_USER_INFO” event before the event is published.

If the subscriber has not subscribed before this event is published, we can publish a Sticky event:

Apollo.instance().sendSticky("SHOW_USER_INFO",user);
Copy the code

Also subscribe at the subscription desk via toObservableSticky:

Apollo.get().toObservableSticky(User.class)
                .subscribe(user -> {
                    //do something.
                }, throwable -> {
                    throwable.printStackTrace();
                }));
Copy the code

In this way, the subscriber will receive the Sticky event in the first time after subscribing. Notice That the Sticky event needs to be manually cleared.

Also note that at the end of the Activity/Fragment life cycle, you must unsubscribe to prevent memory leaks caused by RxJava.

@Override
protected void onDestroy() {
    super.onDestroy();
    if(!subscription.isUnsubscribed()) {
        subscription.unsubscribe();
    }
}
Copy the code

The code above has implemented a simple RxBus.

Based on compile-time annotation processingApollo implementation

Remember the functional requirements for Apollo above?

  1. Events are uniquely identified by tags,
  2. Subscribers only receive events corresponding to tags
  3. An event can be any object
  4. Support for sticky Event functionality (because the Activity that might subscribe to the event has not been started at the time the event is sent)
  5. Apollo is singleton

Now, I’m going to build on that and add some new features to Apollo


  1. I now want to simplify the subscription code by using annotations to implement subscribing to specified tag events:
  2. @Receive(tag ="SHOW_USER_INFO")
    public void receiveUser(User user) {
        Log.d("apollo", "receive user event" + user.toString());
    }
    Copy the code

  3. Control the type of event received by 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());
    }
    Copy the code

  4. Control the scheduler via annotations
    @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());
    }
    Copy the code

  5. Bind and unbind using the following format
    public abstract class BaseActivity extends AppCompatActivity { private SubscriptionBinder mBinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); afterCreate(savedInstanceState); // bind mBinder = apollo.get ().bind(this); } @Override protected void onDestroy() { super.onDestroy(); / / unbundling mBinder. Unbind (); } protected abstract int getLayoutId(); protected abstract void afterCreate(Bundle savedInstanceState); }Copy the code


Since we mentioned earlier that this article only introduces how to implement complie-time Apollo, we will not consider the run-time reflection mechanism implementation here.

Before we start writing Complie-Time Apollo, let’s review Dagger2 and ButterKnife, both of which require at least two modules when used. One of these modules is usually called compiler or Processor, for example:

The compile 'com. Jakewharton: butterknife: 8.2.1 apt' com. Jakewharton: butterknife - compiler: 8.2.1 'Copy the code

The processor is responsible for processing annotations and generating code.

At the same time, since the processor used to generate code at compile time does not need to be packaged into APK, apt is used instead of complie.

Here, I divide the whole Apollo into two parts:

  • One is the core code section, which implements the main functions and provides a binding interface to the Apollo Module.
  • One is to parse all the annotations we need to generate the processor Module that specifies the binding code.


Before writing processor, in fact, the logic of Apollo has almost been completed. The main things that need to be implemented here are:

  • Apollo provides the binding interface, which is implemented by the binding code generated by the Processor, and when initialized, Apollo holds the generated binding interface implementation class instance. This allows binding in BaseActivity via apollo.get.bind().
  • Apollo provide RxJava basic scheduler and AndroidSchedulers. MainThread () at the time of initialization passed as a parameter. (Since Apollo Module is a Java library and cannot rely on RxAndroid as the Android library, the main scheduler needs to be passed when initialized. I’ll talk later about why Apollo and Processor are only Java libraries.)

The SubscriberBinder interface is given here first:

    public interface SubscriberBinder {
        SubscriptionBinder bind(Object object);
    }
Copy the code

The interface is as simple as implementing a bind method and returning a SubscriptionBinder object.

Implementation of SubscriberBinder (for unsubscribing)

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;
        }
    }
}
Copy the code


Add a binding method to Apollo

public SubscriptionBinder bind(Object o) {
if (null == o) {
throw new NullPointerException("object to bind must not be null");
    }
return mSubscriberBinder.bind(o);
}
Copy the code

After the success of the binding, return a SubscriptionBinder object, at the end of the life cycle we can call SubscriptionBinder. Unbind (); Method to unbind all subscribers in the current Activity or Fragment.


Processor implementation

AbstractProcessor before writing a processor, AbstractProcessor is an AbstractProcessor that every annotation processor must inherit (references will be explained below, but I won’t go into detail here) :

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() { }

} 
Copy the code

  • Init (ProcessingEnvironment env):- Initializes the operation method. RoundEnvironment provides many useful utility classes such as Elements, Types and Filer
  • Process (Set annoations, RoundEnvironment env): this is the entry function for scanning annotations, processing, and generating Java code. Attention! If you generate source code in this function, the process method may be called multiple times, because the source code you generate may also have annotations, and the process method continues to process the source file until no source files are generated in the process.

  • GetSupportedAnnotationTypes: return to deal with the annotation type, that is to say, annotation processor only deals with the annotation, this is must be specified.

  • GetSupportedSourceVersion () : used to specify the Java version you use. Usually here return SourceVersion. LatestSupported ().

In Java 7, you can also use annotations to replace getSupportedAnnotationTypes () and getSupportedSourceVersion (), like this:

@ SupportedSourceVersion (SourceVersion latestSupported ()) @ SupportedAnnotationTypes ({/ / a collection of legal note full name}) public class MyProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env){ } @Override public boolean process(Set annoations, RoundEnvironment env) { } }Copy the code

For compatibility reasons, especially for Android, I recommend using overloaded getSupportedAnnotationTypes () and getSupportedSourceVersion instead of @ SupportedAnnotationTypes and @ SupportedSourceVersion () method.

Take effect in order to make the custom Processor, need in the Java directory at the new Processor resources/meta-inf/services/javax.mail annotation. Processing. Processor file

    - com
      -lsxiao
        -apollo
          -processor
            -ApolloAnnotationProcessor.java
    - META-INF
        - services
            - javax.annotation.processing.Processor
Copy the code

Then the javax.mail. The annotation. Processing. To specify a custom Processor file Processor, such as:

com.lsxiao.apollo.processor.ApolloAnnotationProcessor
Copy the code

Multiple processors write line feed.

Then run gradle Build.


If you’re developing more efficiently in compile-time annotation processing, instead of generating source files with string concatenation, you’ll need the following libraries:


Android Studio does not support annotation handlers, but with Android-apt, we can use annotation handlers. This plugin automatically creates directories for your generated code and compiles the generated code into APK. It also allows the resulting APK to be compiled without the annotation processor’s own code,

  • Because this part of the code is only used to generate code at compile time, it is not needed at run time. That is, it has two main purposes:
  • Allows configurations to be used only as annotations processor dependencies at compile time and not added to the final APK or library


Setting the source path so that the code generated by the annotation handler is properly referenced by Android Studio under what circumstances will we need to use it?

  • When you need to import the source code generated by the Processor into your code. For example when you use Dagger 2 or AndroidAnnotaition.
  • This plugin allows Android Studio to configure the build path to generate resources, avoiding IDE errors.
  • When using apt add to add dependencies, it will not be included in the final APK.






The main purpose of Google Auto is to annotate the Processor class and generate meta-INF configuration information for it, so that you don’t have to write meta-INF configuration files. Add @autoService (Processor.class) to your custom Processor.


javapoet:A Java API for generating .java source files. It makes it easier to generate code, and it helps us generate code in the form of class calls.



ApolloAnnotationProcessor.java

@AutoService(Processor.class) public class ApolloAnnotationProcessor extends AbstractProcessor { private ReceiveAnnotationHandler mReceiveAnnotationHandler; //init(): a method for initializing operations. RoundEnvironment provides many useful utility classes, such as Elements, Types and 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 () corresponds to the main function () for each processor. In this method to scan, evaluate, process, and generate Java files. @Override public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) { mReceiveAnnotationHandler.process(roundEnv); return true; } / * * * to specify the annotation processor need to deal with annotation type * * @ the annotation of the return to deal with the Set of type name Set * / @ Override public Set getSupportedAnnotationTypes () {Set types  = new HashSet<>(); types.add(com.lsxiao.apllo.annotations.Receive.class.getCanonicalName()); return types; } /** * Specifies the version of Java to use. Usually there will be directly back into the SourceVersion. LatestSupported (). * * @return SourceVersion */ @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); }}Copy the code


ReceiveAnnotationHandler. Java (out of the process inside parse the Receive tasks, convenient after adding annotation to the later extension)

public class ReceiveAnnotationHandler extends BaseHandler { private Map> mClassMethodMap = new HashMap<>(); / / if new source files generated process () can be called many times, because the generated source file may have comments, they will also be ApolloAnnotationProcessor processing. Private Boolean handleComplete = false; private Boolean handleComplete = false; @Override public void process(RoundEnvironment roundEnv) { if (handleComplete) { return; } / / singleton variable FieldSpec Builder fieldBuilder = FieldSpec. Builder (Apollo. SubscriberBinder. Class, "sInstance." Modifier.PRIVATE, Modifier.STATIC); InstanceMethodBuilder = methodSpec.methodBuilder (" Instance ").modifier (Modifier.PUBLIC) Modifier.STATIC, Modifier.SYNCHRONIZED) .returns(Apollo.SubscriberBinder.class) .beginControlFlow("if (null == sInstance)") .addStatement("sInstance = new SubscriberBinderImplement()") .endControlFlow() .addStatement("return sInstance"); // Bind 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)) {/ / comment most of the lateral must be a 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!" ); ExecutableElement receiveMethodElement = (ExecutableElement) Element; / / find TypeElement annotation belonging to the class 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); } // Storage method 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 method can only have one variable if (methodElement. GetParameters (). The size () > 1) { error("the " + methodElement.toString() + " method in " + classTypeAnnotationIn.toString() + " only support 1 parameter,but there are " + methodElement.getParameters().size()); } / / acquisition method first variable VariableElement eventVariable = methodElement. GetParameters () get (0); / / get the tag value String tag = methodElement. GetAnnotation (Receive) a class). The tag (); Receive.Thread observeOn = methodElement.getAnnotation(Receive.class).observeOn(); Receive.Thread subscribeOn = methodElement.getAnnotation(Receive.class).subscribeOn(); / / whether to obtain receiveMethod Receive sticky event Boolean isSticky = methodElement. GetAnnotation (Receive) a class). The 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(); }}}Copy the code

  • The code above using Javapoet completed a SubscriberBinder interface implementation class, provides a static method can obtain SubscriberBinderImplement singleton.
  • An annotated method can receive only one event parameter
  • The outermost node of the annotated method must be a class
  • Subscribe corresponding tag events for corresponding methods according to tag,type and Thread of annotations, and convert the events to the type when they are sent when they are output. Finally, the thread scheduler is specified in subscribeOn and observeO.

The source files generated in the final demo are as follows

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.annot ations.Receive.Thread.IO)).observeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.MAIN)).sub scribe(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.annot ations.Receive.Thread.IO)).observeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.MAIN)).sub scribe(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.annot ations.Receive.Thread.IO)).observeOn(Apollo.get().getThread().get(com.lsxiao.apllo.annotations.Receive.Thread.MAIN)).sub scribe(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; }}Copy the code

public class App extends Application { @Override public void onCreate() { super.onCreate(); Apollo.get().init(SubscriberBinderImplement.instance(), AndroidSchedulers.mainThread()); }}Copy the code

The above is the whole implementation of complie-time RxBus. You can check the details
Apollo.


Ps. Attention! Again, Apollo is still in unstable release and is not recommended for production before version 0.2.