This article has been authorized to be reproduced by Yu Gang shuo’s wechat official account
Encapsulation optimization
There was an error today encapsulating EventBus into a base class
The Activity itself and its parent class do not have any subscribed methods
So I went back and looked at the encapsulation of EventBus in my company’s project (PS: I didn’t wrap it), and my colleague used placeholder in the base class
But I have a better way of writing it, which is sort of a meaningless subscription method which is not an elegant placeholder, so we can catch this exception so that our App doesn’t crash
We have to think of a problem, the EventBus. When the register if the class does not have to subscribe to complains, so the question comes, if will unsubscribe when an error? Let’s take a quick look at the source code
However, no exceptions are thrown, just a log is simply printed, so there is no need to catch exceptions in the eventBus.unregister method
However, we can optimize it by checking whether the current object is registered with EventBus and unregistering it if it is
The relevant code
public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); try { EventBus.getDefault().register(this); } catch (EventBusException ignored) { // Subscriber class Activity and its super classes have no public methods with the @Subscribe annotation } } @Override protected void onDestroy() { super.onDestroy(); if (EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().unregister(this); }}}Copy the code
APT plug-in
Integrate Apt plug-ins into your project
Android {defaultConfig {javaCompileOptions {annotationProcessorOptions {/ / EventBus Apt index class generation the arguments =" eventBusIndex : ApplicationId + 'MyEventBusIndex']}}}} dependencies {implementation 'org. Greenrobot: eventbus: 3.1.1' AnnotationProcessor 'org. Greenrobot: eventbus -- the annotation processor: 3.1.1'}Copy the code
Initialize the default configuration of EventBus in the Application
// initialize EventBus eventbus.builder ().ignoregeneratedindex (false) // use Apt plugin.addindex (new MyEventBusIndex()) // addIndex class .installDefaultEventBus(); // as the defaultCopy the code
Then select Build -> Rebuild Project, as long as the Project already uses EventBus (the @SUBSCRIBE method in the Project), otherwise there is no way to generate the class
Have a look at this code automatically generated by APT and see if you are enlightened
/** This class is generated by EventBus, do not edit. */ public class MyEventBusIndex implements SubscriberInfoIndex { private static final Map<Class<? >, SubscriberInfo> SUBSCRIBER_INDEX; static { SUBSCRIBER_INDEX = new HashMap<Class<? >, SubscriberInfo>(); putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.fragment.PersonFragment.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onLoginEvent", com.gatewang.ksl.event.LoginEvent.class, ThreadMode.MAIN), new SubscriberMethodInfo("onLoginOutEvent", com.gatewang.ksl.event.LoginOutEvent.class, ThreadMode.MAIN), })); putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.activity.MainActivity.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("goBackHomeEvent", com.gatewang.ksl.event.GoBackHomeEvent.class, ThreadMode.MAIN), })); putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.fragment.SJMBaseFragment.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onEvent", String.class, ThreadMode.MAIN), })); putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.activity.LoginActivity.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onLoginEventEvent", com.gatewang.ksl.event.LoginEvent.class, ThreadMode.MAIN), })); putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.activity.KSLBaseActivity.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onEvent", String.class, ThreadMode.MAIN), new SubscriberMethodInfo("onLoginOutEvent", com.gatewang.ksl.event.LoginOutEvent.class, ThreadMode.MAIN), })); putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.activity.SignInActivity.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onLoginEvent", com.gatewang.ksl.event.LoginEvent.class, ThreadMode.MAIN), })); putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.fragment.ShopCartFragment.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onRefreshShopCartEvent", com.gatewang.ksl.event.RefreshShopCartEvent.class, ThreadMode.MAIN), new SubscriberMethodInfo("onLoginEvent", com.gatewang.ksl.event.LoginEvent.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; }}}Copy the code
Now let’s see what this code is
The Apt plugin generates subscription methods into MyEventBusIndex, so what are the benefits of doing so? Just think about how EventBus works, and how eventBus. register gets information about the @SUBSCRIBE method in this class. Anyone who has used annotations knows that annotations can only be retrieved by reflection. However, the MyEventBusIndex class that EventBus automatically generates with Apt contains all the annotated method information of the class (method name, event object, thread of execution, etc.), because there is no need to retrieve the annotation information through reflection. Because these information has been automatically generated by Apt into a class, eventBus. register will give priority to check whether there is MyEventBusIndex class, if there is, it will get from this class, if not, it will get through reflection. This effectively avoids the performance problems associated with using reflection
The ultimate optimization
After learning Apt, you can write it in a more elegant and better way, so that you don’t need to catch exceptions in code blocks
/ * * * the author: Android wheels elder brother * lot: https://github.com/getActivity/AndroidProject * time: 2019/04/02 * desc: EventBusHelper */ Public Final Class EventBusHelper {// EventBus index class Private Static Final SubscriberInfoIndex SUBSCRIBE_INDEX = new MyEventBusIndex(); EventBus Private static final ArrayMap<String, Boolean> SUBSCRIBE_EVENT = new ArrayMap<>(); Private EventBusHelper() {} public static void init() {eventbus.Builder () public static void init() {eventBus.builder () .installdefaulteventbus () // addIndex class.installdefaulteventbus (); Public static void register(Object subscriber) {if (canSubscribeEvent(subscriber)) {if (canSubscribeEvent(subscriber)) { EventBus.getDefault().register(subscriber); } /** * unregister EventBus */ public static void unregister(Object subscriber) {if (canSubscribeEvent(subscriber) && EventBus.getDefault().isRegistered(subscriber)) { EventBus.getDefault().unregister(subscriber); Private static Boolean canSubscribeEvent(Object subscriber); { Class<? > clazz = subscriber.getClass(); Boolean result = subscribe_event.get (clazz.getName()); if (result ! = null) {return result; } // While (clazz! EventBus if (subscribe_index. getSubscriberInfo(clazz)! = null) {// This class needs to register EventBus result = true; clazz = null; } else { String clazzName = clazz.getName(); // Skip system classes (ignore java.javax.android.androidx. Such as the beginning of the package name) if (clazzName. StartsWith (" Java ") | | clazzName. StartsWith (" android ")) {clazz = null; } else {clazz = clazz.getSuperclass(); EventBus if (result == null) {result = false; } SUBSCRIBE_EVENT.put(subscriber.getClass().getName(), result); return result; } @subscribe (threadMode = threadmode. MAIN) public void onEventBus(EventBusHelper helper) { }}}}}}}}}}}}}}}}}}}}}Copy the code
public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); // Initialize EventBus eventBusHelper.init (); }}Copy the code
public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Register EventBus eventBusHelper. register(this); } @Override protected void onDestroy() { super.onDestroy(); . / / the registered EventBus EventBusHelper unregister (this); }}Copy the code
Why write it that way? In the next article, we’ll take a closer look at the source code for EventBus