EventBus的使用與分析

夕陽下的奔跑發表於2019-08-08
  1. 使用過程

    定義事件:
    public class MessageEvent {
        public final String message;
    
        public MessageEvent(String message) {
            this.message = message;
        }
    }
    複製程式碼
    定義事件回撥(方法名沒有限制):

    在MainActivity中定義事件回撥

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(MessageEvent event) {
    	Toast.makeText(this, event.message, Toast.LENGTH_LONG).show();
    }
    複製程式碼
    EventBus有5種ThreadMode
    public enum ThreadMode {
    	//在傳送事件的執行緒執行回撥
        POSTING,
    	//在主執行緒執行,如果傳送執行緒是主執行緒,則同步執行回撥;如果不是主執行緒,則把回撥放入主執行緒訊息佇列
        MAIN,
    	//直接將回撥放入主執行緒訊息佇列
        MAIN_ORDERED,
    	//回撥在子執行緒中執行。如果傳送執行緒非子執行緒,則直接同步執行回撥;如果是主執行緒,則EventBus會新建一個子執行緒,並把所有的這種型別的事件放到這個執行緒中執行
        BACKGROUND,
    	//子執行緒非同步執行,一般不是主執行緒,也不是事件傳送執行緒
        ASYNC
    }
    複製程式碼
    註冊和解綁EventBus監聽

    如在MainActivity中進行:

    @Override
    protected void onCreate() {
    	super.onCreate();
    	EventBus.getDefault().register(this);
    }
        
    @Override
    protected void onDestroy() {
        super.onDestroy();
    	EventBus.getDefault().unregister(this);
    }
    複製程式碼

    傳送事件:

    EventBus.getDefault().post(new MessageEvent("hello"));
    複製程式碼
  2. 其他情況的處理

    1. 傳送的事件沒有監聽器
      //傳送了字串,但是沒有對應的字串型別的事件回撥
      EventBus.getDefault().post("hello");
      複製程式碼
      if (!subscriptionFound) {
      	if (logNoSubscriberMessages) {
      		logger.log(Level.FINE, "No subscribers registered for event " + 						eventClass);
      	}
          if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
      	    	   eventClass != SubscriberExceptionEvent.class) {
          	post(new NoSubscriberEvent(this, event));
          }
      }
      複製程式碼

      如果配置了EventBusBuilderlogNoSubscriberMessages,會列印日誌;

      如果配置了sendNoSubscriberEvent,則會觸發一個NoSubscriberEvent事件

    2. 黏性事件

      概念:EventBus會為每個事件型別儲存最近一次的事件。當監聽者進行註冊時,會將快取的事件傳送給它。

      使用場景:跨生命週期或者非同步呼叫等場景可以使用

      舉例:從MAinActivity跳轉到SecondActivity時,傳送一個黏性事件;在SecondActivity註冊EventBus時,會觸發該黏性事件

      EventBus.getDefault().postSticky(new MessageEvent("ss"));
      Intent it = new Intent(MainActivity.this, SecondActivity.class);
      MainActivity.this.startActivity(it);
      複製程式碼

      SecondActivity中定義黏性事件的回撥

      @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
      public void process(MessageEvent e){
         Toast.makeText(this, "sticky", Toast.LENGTH_LONG).show();
      }
      複製程式碼

      在onCreate中向EventBus註冊回撥,就會觸發回撥

      EventBus.getDefault().register(this);
      複製程式碼

      原理(黏性事件分發)

      public void postSticky(Object event) {
         synchronized (stickyEvents) {
             //1 每種黏性事件最近的一個例項會被儲存
             stickyEvents.put(event.getClass(), event);
         }
          //2 事件也會繼續分發
         // Should be posted after it is putted, in case the subscriber wants to remove immediately
         post(event);
      }
      複製程式碼

      註冊時的處理邏輯

      private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
          ......
         //註冊時,如果回撥方法是黏性的,則會將儲存的黏性事件分發出去,觸發該回撥方法
         if (subscriberMethod.sticky) {
             if (eventInheritance) {
                 Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                 for (Map.Entry<Class<?>, Object> entry : entries) {
                     Class<?> candidateEventType = entry.getKey();
                     if (eventType.isAssignableFrom(candidateEventType)) {
                         Object stickyEvent = entry.getValue();
                         checkPostStickyEventToSubscription(newSubscription, 			 						stickyEvent);
                     }
                 }
             } else {
                 Object stickyEvent = stickyEvents.get(eventType);
                 checkPostStickyEventToSubscription(newSubscription, stickyEvent);
             }
         }
      }
      複製程式碼
    3. 事件有繼承關係
      • 定義了一個回撥,事件型別是Object
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void process(Object event) {
      	Toast.makeText(this, event.toString(), Toast.LENGTH_LONG).show();
      }
      複製程式碼

      當傳送任意其他型別的事件時,也會觸發這個回撥,原因在EventBus中有一個eventInheritance變數進行控制,預設為true,會響應該事件及其父類的回撥方法

      private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
      	Class<?> eventClass = event.getClass();
          boolean subscriptionFound = false;
          if (eventInheritance) {
              //需要響應該事件的全部事件型別
              List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
              int countTypes = eventTypes.size();
              for (int h = 0; h < countTypes; h++) {
                  Class<?> clazz = eventTypes.get(h);
                  subscriptionFound |= postSingleEventForEventType(event, 									postingState, clazz);
              }
          } else {
              subscriptionFound = postSingleEventForEventType(event, postingState, 															eventClass);
          }
          if (!subscriptionFound) {
              if (logNoSubscriberMessages) {
                  logger.log(Level.FINE, "No subscribers registered for event " + 						eventClass);
              }
              if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
            	       eventClass != SubscriberExceptionEvent.class) {
                  post(new NoSubscriberEvent(this, event));
              }
          }
      }
      複製程式碼

      lookupAllEventTypes方法會遍歷所有的事件型別,包括其父類

      private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
      	synchronized (eventTypesCache) {
              List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
              if (eventTypes == null) {
                  eventTypes = new ArrayList<>();
                  Class<?> clazz = eventClass;
                  while (clazz != null) {
              	    eventTypes.add(clazz);
                      addInterfaces(eventTypes, clazz.getInterfaces());
                      //事件型別的父類,包括Object
                      clazz = clazz.getSuperclass();
                  }
                  eventTypesCache.put(eventClass, eventTypes);
              }
              return eventTypes;
          }
      }
      複製程式碼

      如果不需要響應該事件的父類的回撥,可以將eventInheritance置為false

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          //不使用預設的EventBus例項
          EventBus.builder().eventInheritance(false).installDefaultEventBus();
          EventBus.getDefault().register(this);
      }
      複製程式碼
      • 定義了一個回撥,事件型別是SubMessageEvent,繼承自MessageEvent
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void process(MessageEvent event) {
          Toast.makeText(this, "Object", Toast.LENGTH_LONG).show();
      }
      
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void processSub(SubMessageEvent event) {
          Toast.makeText(this, "SubMessageEvent", Toast.LENGTH_LONG).show();
      }
      複製程式碼

      傳送SubMessageEvent事件,如果eventInheritance為true,會觸發上述兩個回撥,否則只會觸發SubMessageEvent的回撥

      傳送MessageEvent事件,只會觸發MessageEvent的回撥

    4. 訂閱者有繼承關係

      SecondActivity繼承自MainActivity,觸發MessageEvent事件,則SecondActivity能夠響應事件回撥

      //EventBus.findSubscriberMethods()會呼叫findUsingReflection()或findUsingInfo()尋找註冊類上定義的回撥,會遍歷迴圈到父類中使用Subscribe註解的方法
      private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
          FindState findState = prepareFindState();
          findState.initForSubscriber(subscriberClass);
          while (findState.clazz != null) {
              findUsingReflectionInSingleClass(findState);
              //在父類中尋找監聽器
              findState.moveToSuperclass();
          }
          return getMethodsAndRelease(findState);
      }
      
      private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
          FindState findState = prepareFindState();
          findState.initForSubscriber(subscriberClass);
          while (findState.clazz != null) {
              findState.subscriberInfo = getSubscriberInfo(findState);
              if (findState.subscriberInfo != null) {
                  SubscriberMethod[] array = 			 
                  			findState.subscriberInfo.getSubscriberMethods();
                  for (SubscriberMethod subscriberMethod : array) {
                      if (findState.checkAdd(subscriberMethod.method, 
                      			subscriberMethod.eventType)) {
                       	findState.subscriberMethods.add(subscriberMethod);
                      }
                  }
              } else {
                  findUsingReflectionInSingleClass(findState);
              }
              //在父類中尋找監聽器
              findState.moveToSuperclass();
          }
          return getMethodsAndRelease(findState);
      }
      複製程式碼
    5. 錯誤事件

      EventBus提供了AsyncExecutor和ThrowableFailureEvent來捕獲異常,併傳送異常事件

      過程

      1. 建立一個AsyncExecutor例項,配置了執行緒池,EventBus例項,及錯誤事件型別
      2. 執行一個RunnableEx
      3. 捕獲執行時異常,並用EventBus傳送一個錯誤事件
       //AsyncExecutor中的execute方法,引數型別是RunnableEx,需實現run方法,該方法會丟擲異常
    public void execute(final RunnableEx runnable) {
           threadPool.execute(new Runnable() {
               @Override
               public void run() {
                   try {
                       runnable.run();
                   } catch (Exception e) {
                       Object event;
                       try {
                           event = failureEventConstructor.newInstance(e);
                       } catch (Exception e1) {
                           eventBus.getLogger().log(Level.SEVERE, "Original exception:", 												e);
                           throw new RuntimeException("Could not create failure event", 													e1);
                       }
                       if (event instanceof HasExecutionScope) {
                           ((HasExecutionScope) event).setExecutionScope(scope);
                       }
                       eventBus.post(event);
                   }
               }
           });
       }
       
    複製程式碼

    配合ErrorDialogManager可以在接收到錯誤事件時,彈一個DialogFragment

       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
           EventBus.getDefault().register(this);
           //配置錯誤彈窗的標題和內容
           ErrorDialogConfig cfg = new 	
           	ErrorDialogConfig(getResources(),R.string.app_name, R.string.app_name);
           cfg.setEventBus(EventBus.getDefault());
           //建立fragment
           ErrorDialogManager.factory = new ErrorDialogFragmentFactory.Support(cfg);
           //將fragment繫結到activity
           ErrDialogMgr.attachTo(this);
           findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   AsyncExecutor.create().execute(new AsyncExecutor.RunnableEx() {
                       @Override
                       public void run() throws Exception {
                           Object x = null;
                           //丟擲一個空指標異常
                           x.toString();
                       }
                   });
               }
           });
       }
    複製程式碼

    點選按鈕會觸發空指標異常,EventBus觸發一個ThrowableFailureEvent事件,ErrorDialogManager中註冊了對應的回撥,響應後會顯示一個dialog

    注:由於ErrorDialogManagerSupportManagerFragmentHoneycombManagerFragmentonResume()時會呼叫EventBus.register()方法,但是onEventMainThread(ThrowableFailureEvent event)沒有增加@Subscribe(threadMode = ThreadMode.MAIN)註解,會拋異常崩潰。 解決:把這幾個類複製出來,並在onEventMainThread方法上增加註解,能夠彈窗 這個問題已給EventBus提issue

    1. 呼叫了註冊register(),但是沒有定義事件處理回撥,即沒有使用@Subscribe註解

      會丟擲一個異常

      throw new EventBusException("Subscriber " + subscriberClass
                          + " and its super classes have no public methods with the 							@Subscribe annotation");
      複製程式碼
    2. 定義了多個同事件的回撥
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void process1(MessageEvent event) {
          Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
      }
      
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void process2(MessageEvent event) {
          Toast.makeText(this, "process222", Toast.LENGTH_LONG).show();
      }
      複製程式碼

      如果定義了MessageEvent的兩個回撥方法,當觸發MessageEvent事件時,只有第一個方法會執行。

      原始碼解釋:

      EventBus.findUsingInfo()	=>
      FindState.checkAdd()	=>
      FindState.checkAddWithMethodSignature()
      
      private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
      	methodKeyBuilder.setLength(0);
          methodKeyBuilder.append(method.getName());
          methodKeyBuilder.append('>').append(eventType.getName());
      
          String methodKey = methodKeyBuilder.toString();
          Class<?> methodClass = method.getDeclaringClass();
          Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey,
          									methodClass);
          if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
          	// Only add if not already found in a sub class
              return true;
          } else {
              // Revert the put, old class is further down the class hierarchy
              // 如果同一個事件已經定義過回撥,則使用之前的,不會用新方法替換
              subscriberClassByMethodKey.put(methodKey, methodClassOld);
              return false;
          }
      }
      複製程式碼

使用註解

執行時通過反射查詢註解,會有一些效能損失。EventBus提供了註解處理器,在編譯時生成輔助類,提升效能。

使用過程

配置專案的build.gradle:

dependencies {
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
複製程式碼

配置module的build.gradle:

android {
    
    defaultConfig {
        javaCompileOptions {
            // 註解處理器引數配置
            annotationProcessorOptions {
            // 配置引數名和值
            arguments = [ eventBusIndex : 	
                			'com.example.myapplication.EventBusIndex' ]
            }
        }
    }
}


dependencies {
    // 配置註解處理器
    annotationProcessor  'org.greenrobot:eventbus-annotation-processor:3.1.1'
}

複製程式碼

make project之後,在build/source/apt/debug/下可以看到生成的輔助類,可以看到方法有Subscribe註解的類都會把類名與定義的回撥方法都儲存在SUBSCRIBER_INDEX中

package com.example.myapplication;

import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
import org.greenrobot.eventbus.meta.SubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;

import org.greenrobot.eventbus.ThreadMode;

import java.util.HashMap;
import java.util.Map;

/** This class is generated by EventBus, do not edit. */
public class EventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new 	SimpleSubscriberInfo(com.example.hero.myapplication.MainActivity.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("process1", com.example.hero.myapplication.event.MessageEvent.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;
        }
    }
}

複製程式碼

新增生成的輔助類,需要在例項化EventBus之前新增

EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
EventBus.getDefault().register(this);
複製程式碼

註解處理器

註解處理器主要有三個步驟

  1. 收集訂閱者,遍歷每個Subscribe註解,把類和方法儲存到一個ListMap中
  2. 過濾訂閱者,類和方法需要滿足一定的條件
  3. 生成java檔案
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
	...
    collectSubscribers(annotations, env, messager);
    checkForSubscribersToSkip(messager, indexPackage);        
    createInfoIndexFile(index);
	...
    return true;
}
複製程式碼

收集訂閱者

private void collectSubscribers(Set<? extends TypeElement> annotations, 	
							RoundEnvironment env, Messager messager) {
    for (TypeElement annotation : annotations) {
        //遍歷註解,獲取每個加了註解的方法
        Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);
        for (Element element : elements) {
            if (element instanceof ExecutableElement) {
                ExecutableElement method = (ExecutableElement) element;
                //方法不是static,必須是public,且只有一個引數
                if (checkHasNoErrors(method, messager)) {
                    //方法所在的類
                    TypeElement classElement = (TypeElement) 
                    			method.getEnclosingElement();
                    //methodsByClass是一個ListMap
                    methodsByClass.putElement(classElement, method);
                }
            } else {
                messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid 
                		for methods", element);
            }
        }
    }
}
複製程式碼

過濾訂閱者

private void checkForSubscribersToSkip(Messager messager, String myPackage) {
    for (TypeElement skipCandidate : methodsByClass.keySet()) {
        TypeElement subscriberClass = skipCandidate;
        while (subscriberClass != null) {
            //類的修飾符是public,則可見
            //類的修飾符是private或protected,則不可見
            //類的修飾符是預設的,則需要生成的輔助類的包名與註解所在類的包名一樣
            if (!isVisible(myPackage, subscriberClass)) {
                boolean added = classesToSkip.add(skipCandidate);
                if (added) {
                    String msg;
                    if (subscriberClass.equals(skipCandidate)) {
                        msg = "Falling back to reflection because class is not 
                            public";
                    } else {
                        msg = "Falling back to reflection because " + skipCandidate +
                                    " has a non-public super class";
                    }
                    messager.printMessage(Diagnostic.Kind.NOTE, msg, subscriberClass);
                }
                break;
            }
            List<ExecutableElement> methods = methodsByClass.get(subscriberClass);
            if (methods != null) {
                for (ExecutableElement method : methods) {
                    String skipReason = null;
                    VariableElement param = method.getParameters().get(0);
                    TypeMirror typeMirror = getParamTypeMirror(param, messager);
                    //引數型別校驗,DeclaredType表示類或者介面,TypeElement表示類或介面
                    if (!(typeMirror instanceof DeclaredType) ||
                           	!(((DeclaredType) typeMirror).asElement() instanceof 	
                              TypeElement)) {
                        skipReason = "event type cannot be processed";
                    }
                    if (skipReason == null) {
                        TypeElement eventTypeElement = (TypeElement) ((DeclaredType) 								typeMirror).asElement();
                        //類的修飾符是public,則可見
            			//類的修飾符是private或protected,則不可見
           				//類的修飾符是預設的,則需要生成的輔助類的包名與註解所在類的包名一樣
                        if (!isVisible(myPackage, eventTypeElement)) {
                            skipReason = "event type is not public";
                        }
                    }
                    if (skipReason != null) {
                        boolean added = classesToSkip.add(skipCandidate);
                        if (added) {
                            String msg = "Falling back to reflection because " + skipReason;
                            if (!subscriberClass.equals(skipCandidate)) {
                                msg += " (found in super class for " + skipCandidate + ")";
                            }
                            messager.printMessage(Diagnostic.Kind.NOTE, msg, param);
                        }
                        break;
                    }
                }
            }
            subscriberClass = getSuperclass(subscriberClass);
        }
    }
}
複製程式碼

生成java類

//index:在build.gradle中配置的註解處理器的引數——生成類的檔名,包含包名
private void createInfoIndexFile(String index) {
    BufferedWriter writer = null;
    try {
        JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
        int period = index.lastIndexOf('.');
        //解析包名和類名
        String myPackage = period > 0 ? index.substring(0, period) : null;
        String clazz = index.substring(period + 1);
        writer = new BufferedWriter(sourceFile.openWriter());
        if (myPackage != null) {
            writer.write("package " + myPackage + ";\n\n");
        }
        //寫入各種依賴
        writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
        writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
        writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
        writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
        writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
        writer.write("import java.util.HashMap;\n");
        writer.write("import java.util.Map;\n\n");
        writer.write("/** This class is generated by EventBus, do not edit. */\n");
        writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
        //定義靜態常量
        writer.write("    private static final Map<Class<?>, SubscriberInfo> 
                     SUBSCRIBER_INDEX;\n\n");
        writer.write("    static {\n");
        writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>
                     ();\n\n");
        //呼叫putIndex方法,把收集的所有類和類中的全部註解方法儲存到SUBSCRIBER_INDEX中
        writeIndexLines(writer, myPackage);
        writer.write("    }\n\n");
        //定義新增回撥資訊的方法
        writer.write("    private static void putIndex(SubscriberInfo info) {\n");
        writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
        writer.write("    }\n\n");
        //實現介面,獲取類的訂閱資訊,包含了所有有註解的方法資訊
        writer.write("    @Override\n");
        writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> 
                     subscriberClass) {\n");
        writer.write("        SubscriberInfo info = 
                     SUBSCRIBER_INDEX.get(subscriberClass);\n");
        writer.write("        if (info != null) {\n");
        writer.write("            return info;\n");
        writer.write("        } else {\n");
        writer.write("            return null;\n");
        writer.write("        }\n");
        writer.write("    }\n");
        writer.write("}\n");
    } catch (IOException e) {
        throw new RuntimeException("Could not write source for " + index, e);
    } finally {
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException e) {
                //Silent
            }
         }
    }
}
複製程式碼

EventBus對生成類的處理過程

  1. 使用生成的輔助類獲取對應類的訂閱資訊
  2. 將訂閱資訊中的SubscriberMethodInfo轉換為SubscriberMethod
  3. 將每個方法和事件型別新增到對應的Map中
  4. 如果沒有註解生成類,則使用反射來獲取這個類中每個註解方法的資訊
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findState.subscriberInfo = getSubscriberInfo(findState);
        if (findState.subscriberInfo != null) {
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, 
                		subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}
複製程式碼

獲取類的訂閱者資訊

private SubscriberInfo getSubscriberInfo(FindState findState) {
    if (findState.subscriberInfo != null && 
    	findState.subscriberInfo.getSuperSubscriberInfo() != null) {
        SubscriberInfo superclassInfo = 
        	findState.subscriberInfo.getSuperSubscriberInfo();
        if (findState.clazz == superclassInfo.getSubscriberClass()) {
            return superclassInfo;
        }
    }
    if (subscriberInfoIndexes != null) {
        for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            //從輔助類中獲取訂閱資訊
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}
複製程式碼

簡單的效能對比

在一個類中定義多個回撥,增加Subscribe註解,分別使用反射和編譯時註解,比較register()的耗時:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
        long start = System.currentTimeMillis();
        EventBus.getDefault().register(this);
        Log.i("EventBus","register spend="+(System.currentTimeMillis()- start));
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(MessageEvent event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(A event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(B event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(C event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(D event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(E event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(F event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(G event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void process(H event) {
        Toast.makeText(this, "process111", Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}
複製程式碼

多次執行結果:

  1. 使用編譯時註解基本只有方法呼叫的耗時,非常少,日誌顯示為0~1ms
  2. 執行時反射,耗時一般在3~4ms

相關文章