日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

EventBus源码分析

發(fā)布時(shí)間:2025/3/8 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 EventBus源码分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(jiǎn)介

前面我學(xué)習(xí)了如何使用EventBus,還有了解了EventBus的特性,那么接下來(lái)我們一起來(lái)學(xué)習(xí)EventBus的源碼,查看EventBus的源碼,看看EventBus給我們帶來(lái)什么驚喜以及編程思想。

這個(gè)圖我們從一開(kāi)始就一直放置在上面了。我們?cè)趤?lái)回顧一下,EventBus的官網(wǎng)是怎么定義它的呢?
EventBus是Android和Java的發(fā)布/訂閱(觀察者模式)事件總線。
我們大概了解了EventBus的構(gòu)建思想。接下來(lái)我們進(jìn)入源碼學(xué)習(xí)吧。

進(jìn)入源碼分析

我們從EventBus的注冊(cè)開(kāi)始入手。

EventBus.getDefault().register(this); public static EventBus getDefault() {if (defaultInstance == null) {synchronized (EventBus.class) {if (defaultInstance == null) {//創(chuàng)建了EventBus實(shí)例,進(jìn)入下面的方法defaultInstance = new EventBus(); }}}return defaultInstance;}

上面的方法是一個(gè)雙重校驗(yàn)的單例。

public EventBus() {this(DEFAULT_BUILDER); //private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();}

DEFAULT_BUILDER是EventBusBuilder.class實(shí)例來(lái)創(chuàng)建的,這個(gè)類非常重要:使用自定義參數(shù)創(chuàng)建EventBus實(shí)例,還允許自定義默認(rèn)EventBus實(shí)例,如前面的例子使用索引、配置EventBus的配置&事件的優(yōu)先級(jí)&使用索引(四)等就是通過(guò)這個(gè)類來(lái)實(shí)現(xiàn)的,大家可以回顧一下。進(jìn)入初始化一下必要的參數(shù)的構(gòu)造方法EventBus(EventBusBuilder builder),如下

EventBus(EventBusBuilder builder) {logger = builder.getLogger(); /初始化LoggersubscriptionsByEventType = new HashMap<>(); //存儲(chǔ)訂閱事件的typesBySubscriber = new HashMap<>(); //存儲(chǔ)相關(guān)訂閱者class列表,key是注冊(cè)者的對(duì)象,value是訂閱者的class列表stickyEvents = new ConcurrentHashMap<>(); //粘性事件//下面這4個(gè)實(shí)例就是我們?cè)O(shè)置方法``threadMode = ThreadMode.xxx``//*1mainThreadSupport = builder.getMainThreadSupport();mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;backgroundPoster = new BackgroundPoster(this);asyncPoster = new AsyncPoster(this);//獲取注冊(cè)者信息索引(添加由EventBus的注釋預(yù)處理器生成的索引)indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;//初始訂閱方法查找器。這個(gè)類主要具有查找訂閱的方法,繼續(xù)往下看subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);logSubscriberExceptions = builder.logSubscriberExceptions; //是否有日記訂閱,默認(rèn)truelogNoSubscriberMessages = builder.logNoSubscriberMessages;//是否有日記信息,默認(rèn) truesendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;//是否發(fā)送訂閱異常事件,默認(rèn)truesendNoSubscriberEvent = builder.sendNoSubscriberEvent; //是否發(fā)送沒(méi)有訂閱事件,默認(rèn)truethrowSubscriberException = builder.throwSubscriberException; //是否拋出異常處理//默認(rèn)情況下,EventBus會(huì)考慮事件類層次結(jié)構(gòu)(將通知超類的注冊(cè)者)。 關(guān)閉此功能將改善事件的發(fā)布。對(duì)于直接擴(kuò)展Object的簡(jiǎn)單事件類,我們測(cè)量事件發(fā)布的速度提高了20%。eventInheritance = builder.eventInheritance; executorService = builder.executorService; //創(chuàng)建線程池}

我們將此段代碼逐步分析.
這步主要是進(jìn)行初始化話一下必要的參數(shù),如代碼注解所示。
下面這段代碼就是我們常用的@Subscribe(threadMode = ThreadMode.xxx);初始化。一般常用的就是以下4種。

mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this);

我們來(lái)看看builder.getMainThreadSupport()方法返回的是MainThreadSupport接口,表示為支持Android主線程。
上面的4個(gè)線程中都持有 PendingPostQueue 等待發(fā)送的隊(duì)列實(shí)例。
由mainThreadSupport.createPoster(this)創(chuàng)建一個(gè)HandlerPoster而該類繼承了Handle,并且初始化了一個(gè)等待發(fā)布隊(duì)列。代碼如下。

public interface MainThreadSupport {boolean isMainThread();Poster createPoster(EventBus eventBus);class AndroidHandlerMainThreadSupport implements MainThreadSupport {private final Looper looper;public AndroidHandlerMainThreadSupport(Looper looper) {this.looper = looper;}@Overridepublic boolean isMainThread() {return looper == Looper.myLooper();}@Overridepublic Poster createPoster(EventBus eventBus) {return new HandlerPoster(eventBus, looper, 10);}} } subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);

上面代碼在這里主要初始化訂閱的方法查找器。下面會(huì)講解到它是如何進(jìn)行訂閱方法的。
我們這這里知道了EventBus初始化,然后相關(guān)的實(shí)例的創(chuàng)建,接下來(lái)我我們進(jìn)入到register(this)方法的調(diào)用如下方法。

public void register(Object subscriber) {//獲取當(dāng)前注冊(cè)者對(duì)象的Class。Class<?> subscriberClass = subscriber.getClass(); //通過(guò)該注冊(cè)者的`Class`來(lái)獲取當(dāng)前注冊(cè)者里面由`@Subscriber`注解綁定的方法。List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//必須在線程同步中進(jìn)行。synchronized (this) {for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}}

上面的代碼表示的是給注冊(cè)者接收事件。 傳遞當(dāng)前所注冊(cè)的對(duì)象,如Activity、Fragment。

  • 注意: 注冊(cè)者如果不再接收信息,必須調(diào)用unregister(Object)方法,表示解除注冊(cè)則該訂閱者將不再接收到數(shù)據(jù)了,如果不進(jìn)行解除將可能出現(xiàn)內(nèi)存泄漏。一般在onDestroy方法解除注冊(cè)后面會(huì)講解到。 在注冊(cè)者中擁有必須由@Subscribe注解的方法。@Subscribe還允許配置ThreadMode和優(yōu)先級(jí)、是否是粘性行為。

接著,我們進(jìn)入List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);方法。

//private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); //線程安全List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {//從Map集合中獲取訂閱方法列表List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//判斷當(dāng)前獲取方法是否為空if (subscriberMethods != null) {return subscriberMethods;}//通過(guò)EventBusBuilder.ignoreGeneratedIndex//是否忽略配置索引,默認(rèn)是忽略索引if (ignoreGeneratedIndex) {//1.通過(guò)反射獲取方法列表subscriberMethods = findUsingReflection(subscriberClass);} else {//2.通過(guò)索引方式獲取訂閱方法列表subscriberMethods = findUsingInfo(subscriberClass);}//是否訂閱方法為空,如果為空則表示該訂閱者里面的方法都不符合EventBus訂閱方法的規(guī)則if (subscriberMethods.isEmpty()) {throw new EventBusException("Subscriber " + subscriberClass+ " and its super classes have no public methods with the @Subscribe annotation");} else {//存儲(chǔ)到集合中METHOD_CACHE.put(subscriberClass, subscriberMethods);return subscriberMethods;} }

我們逐步分析該段代碼。
該段代碼通過(guò)注冊(cè)者的類來(lái)獲取當(dāng)前dingy的方法列表,如果不為空則直接返回訂閱方法。
通過(guò)反射來(lái)查找訂閱方法,如果該方法為空則拋出異常:該訂閱者的方法和其超類沒(méi)有@Subscriber注解的共有方法(即表示不符合EventBus訂閱方法的規(guī)則)。如果不為空則存儲(chǔ)到ConcurrentHashMap集合中。
這里的是由ConcurrentHashMap集合存儲(chǔ)是以當(dāng)前訂閱者的class為key,而將其由@Subscriber綁定的方法添加到List中,,就是集合的value。必須保持線程安全的,所以這里使用了ConcurrentHashMap。

  • 1.是否忽略索引設(shè)置,該方法表示忽略設(shè)置索引,進(jìn)入該方法findUsingReflection(Class<?> subscriberClass),通過(guò)反射進(jìn)行獲取List<SubscriberMethod>
  • 注:設(shè)置索引在EventBus的配置&事件的優(yōu)先級(jí)&使用索引(四)這里說(shuō)的,大家可以去看看。
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {FindState findState = prepareFindState();//準(zhǔn)備查找狀態(tài)findState.initForSubscriber(subscriberClass);// 初始化訂閱者信息while (findState.clazz != null) {//循環(huán)獲取訂閱者的class是否為空//通過(guò)反射獲取訂閱方法,// 3.該方法下面分析findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); //刪除超類class}獲取訂閱方法listreturn getMethodsAndRelease(findState);}

上面的代碼主要是通過(guò)反射來(lái)獲取相關(guān)的訂閱方法,里面由靜態(tài)內(nèi)部類FindState進(jìn)行管理相關(guān)信息,由于上面的方法和下面索引的方法都將調(diào)用同一個(gè)方法,所以放在下面來(lái)將講解,請(qǐng)看下面信息。

  • 2.是否忽略索引設(shè)置,該方法表示的設(shè)置了索引,進(jìn)入findUsingInfo(Class<?> subscriberClass)方法,如下。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {FindState findState = prepareFindState(); //準(zhǔn)備查找狀態(tài)findState.initForSubscriber(subscriberClass);// 初始化訂閱者信息while (findState.clazz != null) { //循環(huán)獲取訂閱者的class是否為空f(shuō)indState.subscriberInfo = getSubscriberInfo(findState);//獲取獲取訂閱者信息,這里如果使用添加索引的話,這里將能獲取到索引的相關(guān)信息。if (findState.subscriberInfo != null) { //獲取訂閱方法SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();for (SubscriberMethod subscriberMethod : array) {//進(jìn)行等級(jí)檢查,并存儲(chǔ)到Map集合中,該方法checkAdd是FindState.class中的方法 ,key是@Subscriber中參數(shù)的class,value是該subscriberMethod.method,也就是@Subscribe中的方法如:public void onMessageEvent(MessageEvent event)if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {//將該訂閱方法添加到列表中findState.subscriberMethods.add(subscriberMethod);}}} else {//3.通過(guò)使用反射的方式來(lái)獲取,和上面忽略索引調(diào)用到同一個(gè)方法,這里將解析findUsingReflectionInSingleClass(findState);}//清除父類的方法findState.moveToSuperclass();}//獲取訂閱方法listreturn getMethodsAndRelease(findState);}

分析本段代碼。
首先進(jìn)入查找的準(zhǔn)備狀態(tài),通過(guò)默認(rèn)狀態(tài)池返回狀態(tài)信息,主要存儲(chǔ)的是FindState實(shí)例。主要存儲(chǔ)的有訂閱者的class、訂閱者信息SubscriberInfo。訂閱者@Subscribe方法列表List<SubscriberMethod>等.
如果當(dāng)前訂閱者class不為空,則將獲取到訂閱者信息。這里分兩種情況。
如果使用添加索引的話,getSubscriberInfo(findState)該方法將獲取到訂閱信息,如果沒(méi)有使用索引的話則將調(diào)用findUsingReflectionInSingleClass(findState);該方法來(lái)獲取信息

  • 使用添加索引,并返回訂閱方法,該方法如下
//獲取訂閱方法SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();

由于AbstractSubscriberInfo類實(shí)現(xiàn)了SubscriberInfo接口,而SimpleSubscriberInfo繼承了AbstractSubscriberInfo并實(shí)現(xiàn)了getSubscriberMethods方法,代碼如下:
本段代碼在SimpleSubscriberInfo.class中。返回訂閱方法數(shù)組SubscriberMethod[]。

@Overridepublic synchronized SubscriberMethod[] getSubscriberMethods() {int length = methodInfos.length;SubscriberMethod[] methods = new SubscriberMethod[length];for (int i = 0; i < length; i++) {SubscriberMethodInfo info = methodInfos[i];methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,info.priority, info.sticky);}return methods;}
  • 3.如果沒(méi)有添加索引則進(jìn)入該方法findUsingReflectionInSingleClass(findState);

通過(guò)反射來(lái)獲取訂閱者方法。這個(gè)方法有點(diǎn)長(zhǎng),慢慢看。

private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// This is faster than getMethods, especially when subscribers are fat classes like Activities//該方法代替getMethods()方法,獲取該訂閱者class全部方法。methods = findState.clazz.getDeclaredMethods();} catch (Throwable th) {// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149methods = findState.clazz.getMethods(); //獲取該訂閱者class全部方法findState.skipSuperClasses = true; //設(shè)置跳過(guò)超類}for (Method method : methods) {int modifiers = method.getModifiers();//獲取修飾符if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //通過(guò)與運(yùn)算判斷當(dāng)前的修飾符,是否符合EventBus方法定義Class<?>[] parameterTypes = method.getParameterTypes(); //獲取參數(shù)類型if (parameterTypes.length == 1) { //因?yàn)镋ventBus方法中必須有參數(shù),所以當(dāng)參數(shù)為1時(shí),符合要求//通過(guò)注解的形式@Subscribe獲取Subscribe,默認(rèn)的Subscribe為(priority==0,sticky=false,threadMode=POSTING),就是說(shuō)ThreadMode為POSTING,粘性為false,優(yōu)先級(jí)為0,如果方法中設(shè)置了相應(yīng)的值,則將是你設(shè)置的值。如threadMode=MAIN。Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);if (subscribeAnnotation != null) {Class<?> eventType = parameterTypes[0]; //獲取當(dāng)前參數(shù)的class//進(jìn)行等級(jí)檢查,并存儲(chǔ)到Map集合中,該方法checkAdd是FindState.class中的方法 ,key是@Subscriber中參數(shù)的class,value是該subscriberMethod.method,也就是@Subscribe中的方法如:public void onMessageEvent(MessageEvent event)if (findState.checkAdd(method, eventType)) { // 獲取ThreadMode ,如MAINThreadMode threadMode = subscribeAnnotation.threadMode();//將訂閱方法添加到列表中findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));}}} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { //不符合EventBus訂閱方法的規(guī)則要求。拋出異常,提示該方法必須是@Subscribe注解,并且需要一個(gè)參數(shù)String methodName = method.getDeclaringClass().getName() + "." + method.getName();throw new EventBusException("@Subscribe method " + methodName +"must have exactly 1 parameter but has " + parameterTypes.length);}} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {//是一種非法的@Subscribe方法:必須是公共的,非靜態(tài)的,非抽象的String methodName = method.getDeclaringClass().getName() + "." + method.getName();throw new EventBusException(methodName +" is a illegal @Subscribe method: must be public, non-static, and non-abstract");}}}

該段代碼主要是獲取該注冊(cè)者的全部方法,并進(jìn)行篩選出來(lái)符合EventBus的訂閱方法的規(guī)則,通過(guò)注解的形式來(lái)獲取訂閱方法,最后添加到查找狀態(tài)的列表中。
首先獲取的是修飾符,參數(shù)類型,再通過(guò)注解的形式來(lái)獲取訂閱方法。如下注解Subscribe ,如果不符合EventBus相關(guān)訂閱方法的規(guī)則將拋出異常提示,是否在方法上書(shū)寫(xiě)了錯(cuò)誤的方法。
接下來(lái)我們進(jìn)入看看@Subscribe 訂閱方法是通過(guò)注解的形式來(lái)設(shè)置的。

@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe {//ThreadMode ,默認(rèn)POSTINGThreadMode threadMode() default ThreadMode.POSTING;//粘性事件,默認(rèn)falseboolean sticky() default false;//優(yōu)先級(jí),默認(rèn)0int priority() default 0; }

接下來(lái)進(jìn)入getMethodsAndRelease(FindState findState)

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {//獲取到訂閱方法列表List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); //清空回收相關(guān)信息synchronized (FIND_STATE_POOL) {for (int i = 0; i < POOL_SIZE; i++) {if (FIND_STATE_POOL[i] == null) {FIND_STATE_POOL[i] = findState; //將查找狀態(tài)器findState,添加到狀態(tài)池FIND_STATE_POOL中,為下次直接從查找狀態(tài)池中獲取break;}}}return subscriberMethods; // 返回訂閱方法列表}

上面該方法通過(guò)FindState靜態(tài)內(nèi)部類獲取了訂閱的列表,然后被存儲(chǔ)到了ConcurrentHashMap集合中。并且存儲(chǔ)到狀態(tài)池中,為方便下次讀取。并且回收資源。
獲取到List<SubscriberMethod>訂閱列表后,再次回到了注冊(cè)方法中register(Object subscriber)進(jìn)入到方法subscribe(subscriber, subscriberMethod);該方法通過(guò)循環(huán)進(jìn)行遍歷

  • 注 此處必須是在線程同步中進(jìn)行,所以添加synchronized。
//這里的參數(shù)subscriber表示的是訂閱者,如Activity等,subscriberMethod表示訂閱方法,該方法就是在subscriber里面 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {Class<?> eventType = subscriberMethod.eventType; //獲取事件類型,也就是參數(shù)的classSubscription newSubscription = new Subscription(subscriber, subscriberMethod);//通過(guò)事件類型參數(shù)class獲取CopyOnWriteArrayList<Subscription>列表,該類大家可以研究一下,//是寫(xiě)時(shí)復(fù)制容器,即當(dāng)我們往`CopyOnWriteArrayList`容器添加元素時(shí),先從原有的數(shù)組中拷貝一份出來(lái),然后在新的容器做寫(xiě)操作(添加元素),寫(xiě)完之后,再將原來(lái)的數(shù)組引用指向到新數(shù)組的形式存儲(chǔ)數(shù)據(jù)的,它是線程安全的。CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions == null) {subscriptions = new CopyOnWriteArrayList<>();subscriptionsByEventType.put(eventType, subscriptions); //添加到Map集合中} else {if (subscriptions.contains(newSubscription)) { //是否已經(jīng)存在了throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);}}int size = subscriptions.size();for (int i = 0; i <= size; i++) {if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { //判斷優(yōu)先級(jí)subscriptions.add(i, newSubscription);//優(yōu)先級(jí)高的添加添加到CopyOnWriteArrayList容器最前面,只有一個(gè)的時(shí)候就是添加在第一位了。break;}}//獲取訂閱事件的class列表,即訂閱方法的參數(shù)class列表List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();//存儲(chǔ)到Map集合,key是訂閱者(即上面?zhèn)鬟f的Activity對(duì)象),value是訂閱事件列表typesBySubscriber.put(subscriber, subscribedEvents);}subscribedEvents.add(eventType); //將該事件類型class添加到訂閱事件列表中判斷當(dāng)前方法是否是粘性的if (subscriberMethod.sticky) {if (eventInheritance) {//必須考慮eventType的所有子類的現(xiàn)有粘性事件// Existing sticky events of all subclasses of eventType have to be considered.// Note: Iterating over all events may be inefficient with lots of sticky events,// thus data structure should be changed to allow a more efficient lookup// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();for (Map.Entry<Class<?>, Object> entry : entries) {Class<?> candidateEventType = entry.getKey();isAssignableFrom(Class<?> cls)方法表示的類型是否可以通過(guò)標(biāo)識(shí)轉(zhuǎn)換或通過(guò)擴(kuò)展引用轉(zhuǎn)換為此類對(duì)象表示的類型,則返回trueif (eventType.isAssignableFrom(candidateEventType)) {Object stickyEvent = entry.getValue();//將粘性事件添加到訂閱者列表中checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}} else {//將粘性事件添加到訂閱者列表中Object stickyEvent = stickyEvents.get(eventType);checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}}

上面的方法中主要是通過(guò)獲取"事件類型"即訂閱方法中的參數(shù)class。然后將其添加到Map集合中,這里用到了CopyOnWriteArrayList(原理:是寫(xiě)時(shí)復(fù)制容器,即當(dāng)我們往CopyOnWriteArrayList容器添加元素時(shí),先從原有的數(shù)組中拷貝一份出來(lái),然后在新的容器做寫(xiě)操作(添加元素),寫(xiě)完之后,再將原來(lái)的數(shù)組引用指向到新數(shù)組的形式存儲(chǔ)數(shù)據(jù)的,它是線程安全的。)
然后進(jìn)行判斷是否設(shè)置優(yōu)先級(jí),遍歷并添加到subscriptions列表中。
通過(guò)當(dāng)前的注冊(cè)者,獲取注冊(cè)者class列表,并添加到typesBySubscriber集合中,key是注冊(cè)者的class,如:Activity,而value就是訂閱方法中的參數(shù)class的列表。這個(gè)地方說(shuō)明了,一個(gè)注冊(cè)者,可以擁有多個(gè)訂閱事件(方法),將其綁定起來(lái),存儲(chǔ)到Map集合中。最后將該參數(shù)class添加到subscribedEvents.add(eventType);列表中。
下面方法是檢查粘性事件訂閱發(fā)送事件方法,如下

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {if (stickyEvent != null) {// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)// --> Strange corner case, which we don't take care of here.//這段代碼我們到post發(fā)送事件的調(diào)用的時(shí)候講解。postToSubscription(newSubscription, stickyEvent, isMainThread());}}
  • 注:這里主要是檢查是否發(fā)送粘性發(fā)送事件,方法 postToSubscription我們到發(fā)送事件POST方法調(diào)用時(shí)講解。
  • 事件發(fā)送

接下來(lái)我進(jìn)入post方法,事件發(fā)送。此時(shí),我們回憶一下簡(jiǎn)介中的圖:
post()==>EventBus==>將分發(fā)到各個(gè)訂閱事件中。也就是訂閱方法。我們來(lái)看看是如何進(jìn)行操作的。代碼如下

EventBus.getDefault().post(new MessageEvent(message));

通過(guò)以上代碼我大概的知道,post()方法里面的參數(shù)是一個(gè)實(shí)體的對(duì)象,而該實(shí)體就是我們?cè)谟嗛喎椒ㄖ械膮?shù)實(shí)體。你發(fā)現(xiàn)了什么了嗎?
前邊我們已經(jīng)分析了,該注冊(cè)者的訂閱方法主要的存儲(chǔ)過(guò)程,接下來(lái)我們一起進(jìn)入探究吧。方法跟蹤進(jìn)入post()方法。

/** Posts the given event to the event bus. *///給訂閱事件,發(fā)送事件總線public void post(Object event) {//獲取當(dāng)前線程,即通過(guò)ThreadLocal本地線程來(lái)管理對(duì)應(yīng)的事件線程,并且初始化發(fā)送線程狀態(tài)PostingThreadStatePostingThreadState postingState = currentPostingThreadState.get();List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); //添加到事件隊(duì)列中//判斷當(dāng)前發(fā)送線程狀態(tài)是否是正在發(fā)送的事件if (!postingState.isPosting) {postingState.isMainThread = isMainThread();postingState.isPosting = true;if (postingState.canceled) {throw new EventBusException("Internal error. Abort state was not reset");}try {while (!eventQueue.isEmpty()) {//發(fā)送事件,發(fā)送完一個(gè)刪除一個(gè),直到發(fā)送全部停止循環(huán)postSingleEvent(eventQueue.remove(0), postingState);}} finally {//設(shè)置標(biāo)志改變postingState.isPosting = false;postingState.isMainThread = false;}}}

currentPostingThreadState.get()方法中我們知道

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}};

通過(guò)ThreadLocal這里就叫"本地線程"吧,來(lái)管理當(dāng)前的發(fā)送線程狀態(tài),每個(gè)發(fā)送線程將得到對(duì)應(yīng)一個(gè)PostingThreadState,而該P(yáng)ostingThreadState管理eventQueue信息,該信息主要存儲(chǔ)的是發(fā)送事件。
通過(guò)eventQueue.add(event)存儲(chǔ)該發(fā)送事件以后完成以后,就判斷當(dāng)前的發(fā)送事件狀態(tài)是否是正在發(fā)送中,如果還沒(méi)發(fā)送則當(dāng)該eventQueue不為為空的時(shí)候,進(jìn)入循環(huán)發(fā)送該事件,發(fā)送完一個(gè)就刪除一個(gè),直到發(fā)送完成為止。
進(jìn)入方法postSingleEvent(Object event, PostingThreadState postingState)中。

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);//發(fā)送事件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));}}}

上面的方法首先獲取該事件類型的class然后傳遞到lookupAllEventTypes(eventClass)方法中,通過(guò)該方法獲取當(dāng)前發(fā)送事件的class,包括父類、實(shí)現(xiàn)的接口等等列表。所以一般情況下會(huì)返回當(dāng)前發(fā)送的事件,和Object.class(注:當(dāng)然了,如果該事件實(shí)現(xiàn)接口的話,也會(huì)包括實(shí)現(xiàn)的接口的。)列表即List<Class<?>>,然后進(jìn)行遍歷進(jìn)行或運(yùn)算。
我們先進(jìn)入lookupAllEventTypes(eventClass)方法,看看返回的事件類型,并且知道他存儲(chǔ)到Map集合中,即key是當(dāng)前事件class,value是該事件的所有類型,包括父類,接口等。

/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {//private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>(); key是當(dāng)前事件類型的class,valu則是事件的所有類型,包括父類,接口等。本事例會(huì)得到的是MessageEvent.class、和Object.classsynchronized (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());clazz = clazz.getSuperclass(); //獲取父類class}eventTypesCache.put(eventClass, eventTypes); //存儲(chǔ)d}return eventTypes;}}

看看方法postSingleEventForEventType(event, postingState, clazz),發(fā)送事件

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {CopyOnWriteArrayList<Subscription> subscriptions;synchronized (this) {//通過(guò)當(dāng)前的事件class,獲取訂閱事件列表subscriptions = subscriptionsByEventType.get(eventClass);}if (subscriptions != null && !subscriptions.isEmpty()) {for (Subscription subscription : subscriptions) {//對(duì)PostingThreadState進(jìn)行賦值postingState.event = event;postingState.subscription = subscription;boolean aborted = false;try {//發(fā)送事件postToSubscription(subscription, event, postingState.isMainThread);aborted = postingState.canceled;} finally {//設(shè)置參數(shù)為空postingState.event = null;postingState.subscription = null;postingState.canceled = false; //設(shè)置標(biāo)志}if (aborted) {break;}}return true;}return false;}

大家是否還記得在注冊(cè)的時(shí)候出現(xiàn)的CopyOnWriteArrayList<Subscription>在這里就用到了,通過(guò)發(fā)送事件的class獲取CopyOnWriteArrayList容器里面的訂閱事件信息,包括注冊(cè)者對(duì)象,訂閱方法等。然后遍歷并進(jìn)行發(fā)送事件。在此方法發(fā)布postToSubscription()事件

/*** subscription:發(fā)布訂閱的事件處理器* event:當(dāng)前發(fā)布的事件* isMainThread:是否是在主線程中*/ private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {switch (subscription.subscriberMethod.threadMode) {case POSTING:invokeSubscriber(subscription, event);break;case MAIN:if (isMainThread) {invokeSubscriber(subscription, event);} else {mainThreadPoster.enqueue(subscription, event);}break;case MAIN_ORDERED:if (mainThreadPoster != null) {mainThreadPoster.enqueue(subscription, event);} else {// temporary: technically not correct as poster not decoupled from subscriberinvokeSubscriber(subscription, event);}break;case BACKGROUND:if (isMainThread) {backgroundPoster.enqueue(subscription, event);} else {invokeSubscriber(subscription, event);}break;case ASYNC:asyncPoster.enqueue(subscription, event);break;default:throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);}}

好了,這就是之前我們?cè)谧?cè)中有一個(gè)地方遺留下的,就是判斷是否是粘性狀態(tài)是調(diào)用的方法,大家往回看,就看到了在方法checkPostStickyEventToSubscription中有調(diào)用到該方法。
這里會(huì)根據(jù),在方法中所選的threadMode進(jìn)行調(diào)用,

  • 1.MAIN,如果當(dāng)前是否是UI線程,則會(huì)進(jìn)入到invokeSubscriber(subscription, event);方法中。否則將調(diào)用mainThreadPoster.enqueue(subscription, event);這個(gè)方法將交給HandlerPoster.class里面的enqueue(Subscription subscription, Object event)方法,HandlerPoster.class現(xiàn)實(shí)了該接口,移交給handle完成,大家可以進(jìn)入HandlerPoster.class看看,這里就不說(shuō)了。
  • 2.POSTING直接調(diào)用 invokeSubscriber(subscription, event);
  • 3.MAIN_ORDERED如果當(dāng)前mainThreadPoster不為空則調(diào)用 mainThreadPoster.enqueue(subscription, event);和MAIN進(jìn)入HandlerPoster.class,反之調(diào)用invokeSubscriber(subscription, event);
  • 4.BACKGROUND如果當(dāng)前是主線程,則調(diào)用backgroundPoster.enqueue(subscription, event);,反之調(diào)用invokeSubscriber(subscription, event);
  • 5.ASYNC,異步方法調(diào)用,執(zhí)行 asyncPoster.enqueue(subscription, event);,方法進(jìn)行跟蹤,該類有實(shí)現(xiàn)了Runnable接口,然后調(diào)用eventBus.invokeSubscriber(pendingPost);,最終將調(diào)用了invoke方法。
void invokeSubscriber(Subscription subscription, Object event) {try {subscription.subscriberMethod.method.invoke(subscription.subscriber, event);} catch (InvocationTargetException e) {handleSubscriberException(subscription, event, e.getCause());} catch (IllegalAccessException e) {throw new IllegalStateException("Unexpected exception", e);}}

invoke()這是一個(gè)本地的方法,將調(diào)用C/C++的到方法進(jìn)行發(fā)布。最后將進(jìn)入到訂閱方法中。并傳遞該事件到到訂閱的方法中。
好了,這里我們將post發(fā)布事件的方法簡(jiǎn)單的分析了一下。整個(gè)EventBus的分析差不多完成了,但是,我們還有一點(diǎn)不能忘記就是解除綁定。接下來(lái)我們來(lái)看看解除綁定的方法。

  • 注:該方法一般生命周期的onDestroy()方法中進(jìn)行解除綁定。

代碼如下:

EventBus.getDefault().unregister(this);

直接進(jìn)入unregister(this)

/** Unregisters the given subscriber from all event classes. */public synchronized void unregister(Object subscriber) {List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);if (subscribedTypes != null) {for (Class<?> eventType : subscribedTypes) {unsubscribeByEventType(subscriber, eventType);}typesBySubscriber.remove(subscriber);} else {logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());}} /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. *//*** subscriber:指代當(dāng)前解除注冊(cè)的對(duì)象如Activity,* eventType:發(fā)送的事件類型,post函數(shù)的實(shí)體對(duì)象class*/ private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions != null) {int size = subscriptions.size();for (int i = 0; i < size; i++) {Subscription subscription = subscriptions.get(i);if (subscription.subscriber == subscriber) {subscription.active = false;subscriptions.remove(i); //刪除i--; //目的是減少遍歷次數(shù)size--;}}} }

解除綁定,這里很簡(jiǎn)單。這里就不一一進(jìn)行解釋了,^_^。

總結(jié)

1.本篇文章主要對(duì)EventBus源碼進(jìn)行簡(jiǎn)單的分析。主要是進(jìn)行了觀察者模式的一些高級(jí)運(yùn)用。如果大家對(duì)觀察者模式理解不怎么清楚可以進(jìn)入這里看看簡(jiǎn)單的案例觀察者模式,內(nèi)容非常簡(jiǎn)單。
2.相關(guān)的EvenBut的使用,請(qǐng)看之前的內(nèi)容。如EventBus認(rèn)識(shí)(一)EventBus的ThreadMode使用以及分析(二)等等。
3.學(xué)習(xí)本篇文章中可以認(rèn)識(shí)到一些常用的類如CopyOnWriteArrayList、ThreadLocal等,到時(shí)可以深入研究一下,有助我們提高。
4.一些編程思想,設(shè)計(jì)模式值得我們?nèi)W(xué)習(xí)的,如單例模式EventBus雙重校驗(yàn)、建造者模式,EventBus構(gòu)造器的時(shí)候用到,用了初始化各個(gè)參數(shù)等等。面向接口編程而不針對(duì)實(shí)現(xiàn)編程。
5.如果有什么問(wèn)題希望大家進(jìn)行指正,好好學(xué)習(xí),一起進(jìn)步。

總結(jié)

以上是生活随笔為你收集整理的EventBus源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 在线观看的黄色网址 | 欧美一区二区在线观看 | 天堂资源在线播放 | 国产97自拍 | 日本高清视频在线 | 中文免费av| 国产精品99久久久久久大便 | 日韩欧美视频在线播放 | 在线观看 中文字幕 | 好吊一区二区三区视频 | 中国一级特黄毛片大片 | 国产精品一区二区三区免费 | 欧美视频三区 | 久久久夜夜 | 99久久国产宗和精品1上映 | 国产精品国产三级国产aⅴ下载 | 亚洲午夜电影网 | 久久久久久久亚洲精品 | 久操精品在线 | 亚洲激情偷拍 | 亚洲va中文字幕 | 91婷婷射| 国产91视频在线 | 天天操夜夜操 | 国产一区不卡在线 | 国产小视频一区 | 免费在线中文字幕 | 久久亚洲伊人 | 操大爷影院 | 黄色网战在线观看 | 亚洲最新av网站 | 日韩精品一区二区在线观看 | 色网网站 | 九色在线观看 | 狠狠撸在线观看 | 五月天婷婷激情网 | 欧美大胆a| av中文资源 | a国产免费 | 91蜜桃 | 亚洲成人国产精品 | 天堂素人 | 99热一区二区三区 | 美丽的姑娘在线观看免费 | 国产免费黄色片 | 不卡av在线| 日韩城人免费 | 亚洲成人一| 91精品国自产在线偷拍蜜桃 | 国产毛片电影 | 色乱码一区二区三在线看 | 日韩视频一区二区三区在线播放免费观看 | 在线免费观看视频 | 最新中文字幕在线视频 | 加勒比综合 | 欧美色综合色 | 久久久精品人妻一区二区三区色秀 | 一区免费在线 | 国产一级影片 | 在线观看一区 | 日韩人妻一区二区三区蜜桃视频 | 视频在线观看一区二区三区 | 天天射夜夜操 | 中文字幕一区二区在线老色批影视 | av黄色网址 | 日本一级三级三级三级 | 亚洲精品在线视频观看 | 欧美日韩中文字幕一区二区三区 | 亚洲精品a级 | 理论片高清免费理伦片 | 国产suv精品一区二区60 | 亚洲狠狠婷婷综合久久久久图片 | 久久久在线视频 | 久久亚洲国产成人精品性色 | 久久成人精品一区二区 | 麻豆自拍视频 | 久久国产精品久久久 | 日本熟妇乱子伦xxxx | 美女又黄又爽 | yes4444视频在线观看 | 欧洲精品在线播放 | 国产免费激情 | 毛片网站入口 | 欧美视频免费看 | 中文字幕人妻一区二 | 欧美色图11p | 夜夜夜影院 | 一级片在线观看视频 | 欧美精品首页 | 中文字幕人乱码中文字 | 国语对白清晰刺激对白 | 麻豆免费在线播放 | 97xxx| 色老汉视频 | 三级在线国产 | 少妇人妻偷人精品一区二区 | 狠狠综合久久 | 欧美一区二区三区成人精品 | 97国产精品久久 |