EventBus parsing
Basic use of EventBus
1- Defines the event entity to be passed
public class MsgEvent { }
Copy the code
2- Register and unregister your subscribers
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
Copy the code
3- Subscriber: Declare and annotate the subscription method
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MsgEvent event) {
Log.d("OK");
}
Copy the code
4- Send events
EventBus.getDefault().post(new MsgEvent());
Copy the code
Difference between EventBus 3.x and 2.x usage
1- Defines the event entity to be passed
public class MsgEvent { }
Copy the code
2- Register and unregister your subscribers
Eventbus.getdefault ().register(this); Eventbus.getdefault ().register(this); EventBus.getDefault().register(this, 100); EventBus.getDefault().registerSticky(this, 100); EventBus.getDefault().registerSticky(this); Eventbus.getdefault ().unregister(this); eventbus.getDefault ().Copy the code
3- Subscriber: Declare and annotate the subscription method
Subscribe(threadMode = threadmode. BACKGROUND, sticky = true, Priority = 100) public void test(String STR) {} //2.x version public void onEvent(String STR) {} public void onEventMainThread(String str) { } public void onEventBackgroundThread(String str) { }Copy the code
4- Send events
Eventbus.getdefault ().post(" STR "); EventBus.getDefault().postSticky("str");Copy the code
Use of EventBus 3.x new features
EventBusAnnotationProcessor
EventBus2 uses Java reflection to iterate over fetch methods at runtime, and reflection has a performance cost. Use compile-time annotation since EventBus3, compile time using EventBusAnnotationProcessor annotation processor @ the Subscribe contains information, generate index class to save the subscriber and Subscribe to the relevance of information, Make it aware of the methods associated with subscription events before the eventbus.register () method is called.
The use of EventBusAnnotationProcessor
To use this new feature in EventBus 3, the following steps are required:
Add dependencies:
The compile 'org. Greenrobot: eventbus: 3.0.0'Copy the code
Since annotations depend on android-apt-plugin, we need to introduce apt in the dependencies of the project gradle
The classpath 'com. Neenbedankt. Gradle. Plugins: android - apt: 1.8'Copy the code
Build. Gradle for app Module with apt plugin and set the package name and class name of index generated by APT. If you do not set the package name and class name of index generated by APT, an error will be reported during compilation
apply plugin: 'com.neenbedankt.android-apt'
apt {
arguments {
eventBusIndex "com.demo.eventbusannotationsample.MyEventBusIndex"
}
}
Copy the code
Finally, you need to introduce EventBusAnnotationProcessor in app module dependencies
Apt 'org. Greenrobot: eventbus -- the annotation processor: 3.0.1'Copy the code
After completing the above steps, recompile, can be in the app/build/generated/source/apt/debug/see the generated under MyEventBusIndex class
After recompiling, before using EventBus for the first time (such as in Application or SplashActivity), add the following code for Index to take effect:
EventBus eventBus=EventBus.builder().addIndex(new MyEventBusIndex()).build();
Copy the code
It is important to note that if you don’t use EventBusAnnotationProcessor, 3 the EventBus parsing speed will be slower than the previous version.
EventBus principle
Defining the threading model
Public enum ThreadMode {/** * ThreadMode */ BACKGROUND, /** * ThreadMode */ MAIN}Copy the code
Annotations that define subscription event methods
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.MAIN;
}
Copy the code
Defining subscription methods
Public class SubscriberMethod {// private Method Method; Class private class <? > eventType; Private ThreadMode ThreadMode; public SubscriberMethod(Method method, Class<? > eventType, ThreadMode threadMode) { this.method = method; this.eventType = eventType; this.threadMode = threadMode; } public Method getMethod() { return method; } public Class<? > getEventType() { return eventType; } public ThreadMode getThreadMode() { return threadMode; }}Copy the code
Custom event bus
public class MyEventBus { private static volatile MyEventBus instance; // Object corresponds to an Activity or any class, List<SubscriberMethod> Methods that use Subscriber annotations in the corresponding class Private Map<Object, List<SubscriberMethod>> cacheMap; Private Handler mHandler; private MyEventBus() { cacheMap = new HashMap<>(); mHandler = new Handler(Looper.getMainLooper()); } // singleton public static MyEventBus getDefault() {if (instance == null) {synchronized (myeventbus.class) {if (instance == null) { instance = new MyEventBus(); } } } return instance; Public void register(Object obj) {public void register(Object obj) {public void register(Object obj) { Save to Map List<SubscriberMethod> List = cachemap.get (obj); if (list == null) { list = getSubscriberMethodReflection(obj); if (list.size() > 0) { cacheMap.put(obj, list); }} /** * Reflect the Subscriber annotation method in the fetch class ** @param obj class containing subscription events * @return class subscription events collection */ private List<SubscriberMethod> getSubscriberMethodReflection(Object obj) { List<SubscriberMethod> list = new ArrayList<>(); Class<? > clazz = obj.getClass(); while (clazz ! = null) { String name = clazz.getName(); if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.") || Name. StartsWith ("androidx.")) {// The system does not have a Subscribe annotation method, just jump out of the loop break; } Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { Subscribe subscribe = method.getAnnotation(Subscribe.class); If (subscribe == null) {// Not subscribe annotation method continue; } Class<? >[] types = method.getParameterTypes(); if (types.length ! = 1) {throw new RuntimeException(" method parameters are not unique "); } // add Subscribe to the List ThreadMode ThreadMode = subscribe.threadmode (); SubscriberMethod subscriberMethod = new SubscriberMethod(method, types[0], threadMode); list.add(subscriberMethod); } // loop over the Subscribe annotation method in the parent class clazz = clazz.getsuperclass (); } return list; } /** * The logic in the POST method is to call the method in a class that uses the Subscriber annotation; Public void post(final Object msgEvent) {Set<Object> Set = cachemap.keySet (); Iterator<Object> iterator = set.iterator(); While (iterator.hasnext ()) {// Final Object obj = iterator.next(); List<SubscriberMethod> list = cacheMap.get(obj); for (final SubscriberMethod subscriberMethod : List) {/ / to determine whether a message type and subscribe method of the same type if (subscriberMethod. GetEventType () isAssignableFrom (msgEvent. GetClass ())) {/ / thread; Determine the Subscriber annotation method in which a thread executing the switch (subscriberMethod. GetThreadMode ()) {/ / Subscriber annotation method in the MAIN thread execution case MAIN: // Post is executed on the main thread, Call the subscriberMethod method if (looper.myLooper () == Looper.getMainLooper()) {invoke(subscriberMethod, obj, msgEvent); } else {// Execute post on child thread, Mhandler. post(new Runnable() {@override public void run() { invoke(subscriberMethod, obj, msgEvent); }}); } break; // Subscriber annotation method executes case BACKGROUND on child thread: If (looper.myLooper () == looper.getMainLooper ()) {// TODO the original EventBus // TODO uses PendingPostQueue to process messages} else {// Post is also executed on child threads, Call subscriberMethod invoke directly (subscriberMethod, obj, msgEvent); } break; default: break; }}}}} /** * Reflect the Subscriber annotation method in the calling class ** @param subscriberMethod Subscriber annotation method * @param obj class to subscribe to events * @param MsgEvent Subscribe event instance */ private void invoke(SubscriberMethod Subscribe Method, Object obj, Object msgEvent) { Method method = subscriberMethod.getMethod(); method.setAccessible(true); try { method.invoke(obj, msgEvent); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }}}Copy the code
APT Optimization principle of EventBus
MyEventBusIndex
/** * Analog APT optimization * No longer uses reflection to get the Subscriber annotation method in class * but code to get the Subscriber annotation method in class */ public class MyEventBusIndex {private static final Map<Object, List<SubscriberMethod>> cacheMap = new HashMap<>(); static { cacheMap.put(MainActivity.class.getSimpleName(), getSubscriberMethodMain()); cacheMap.put(Main2Activity.class.getSimpleName(), getSubscriberMethodMain2()); } public static List<SubscriberMethod> getSubscriberMethods(Object obj) {return cacheMap.get(obj.getClass().getSimpleName()); Private static List<SubscriberMethod> getSubscriberMethodMain() { List<SubscriberMethod> methodList = new ArrayList<>(); Try {// Add known class and method names to the SubscriberMethod The methodList add multiple SubscriberMethod methodList. Add (new SubscriberMethod (MainActivity. Class. GetMethod (" getMsgEvent ", MsgEvent.class), MsgEvent.class, ThreadMode.MAIN)); } catch (NoSuchMethodException | SecurityException e) { e.printStackTrace(); } return methodList; Private static List<SubscriberMethod> getSubscriberMethodMain2() { List<SubscriberMethod> methodList = new ArrayList<>(); try { methodList.add(new SubscriberMethod( Main2Activity.class.getMethod("getMsgEvent", MsgEvent.class), MsgEvent.class, ThreadMode.MAIN)); } catch (NoSuchMethodException | SecurityException e) { e.printStackTrace(); } return methodList; }}Copy the code
Reflection is no longer used when registering MyEventBus
Public void register(Object obj) {public void register(Object obj) {public void register(Object obj) { Save to Map List<SubscriberMethod> List = cachemap.get (obj); If (list = = null) {/ / through MyEventBusIndex direct access to the Subscriber list = MyEventBusIndex annotation method. The getSubscriberMethods (obj); if (list.size() > 0) { cacheMap.put(obj, list); }}}Copy the code
References:
Explain how to use EventBus 3.0
EventBus 3.0 source code analysis
Efficient use and source code parsing of EventBus 3.0
Parsing EventBusAnnotationProcessor
Deep understanding of EventBus source code
Hand rolled EventBus
EventBus goes from starter to setup