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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

EventBus1.0.1源码解析

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

很久沒有更新過源碼解析類文章,以下內(nèi)容作為源碼分析類的筆記。分析方法適用于其它源碼分析。

分析工具說明

許久以來,閱讀源代碼最得力的工具就非Source Insight莫屬了。然,后來微軟出了一款輕量級但功能強(qiáng)大的IDE就沒Source Insight什么事了。微軟的這款I(lǐng)DE就是大名鼎鼎的VSCODE,全名叫:Visual Studio Code。它的強(qiáng)大之處這里就不過多描述了。我們轉(zhuǎn)回到正題。

獲取源碼并導(dǎo)入IDE

我們在Github.com上搜索到EventBus的項(xiàng)目地址,然后進(jìn)行克隆即可。

git clone https://github.com/greenrobot/EventBus.git

克隆完成之后,導(dǎo)入IDE。打開VS CODE,在菜單欄中選擇File -> Open,選擇克隆后文件所在的目錄,然后點(diǎn)擊確認(rèn)。這就完成了代碼導(dǎo)入工作。

由于我們只是分析EventBus的骨架脈絡(luò),所以我們要選擇EventBus的早期版本。這里我們將要選擇V1.0.1版。這同樣適用于Android源代碼分析,適宜選擇1.5版或1.6版。

切換版本的步驟為:先進(jìn)入EventBus剛才的克隆目錄,然后執(zhí)行以下步驟:

//列出EventBus項(xiàng)目的所有tag。sahadevs-MacBook-Pro:EventBus sahadev$ git tagV1.0.1V2.2.0V2.3.0V2.4.0V3.0.0//上面可以看出EventBus共發(fā)布了5個(gè)版本。我們切換到V1.0.1版。sahadevs-MacBook-Pro:EventBus sahadev$ git checkout V1.0.1

經(jīng)過以上步驟,我們的代碼就切換到了V1.0.1版本。VS CODE中的內(nèi)容也會(huì)同步更新。接下來開始我們的代碼分析。

事件監(jiān)聽注冊

我們熟知EventBus的用法,其中最有代表性的入口為:

EventBus.getDefault().register(this);

為了方便分析,上面這行代碼放在Activity中執(zhí)行。所以上面的this就是Activity的實(shí)例。EventBus采用了單例模式,在這個(gè)版本中,采用了最簡便的實(shí)現(xiàn)方式:

public class EventBus {private static final EventBus defaultInstance = new EventBus();public static EventBus getDefault() {return defaultInstance;} }

好,以上并不是我們的重點(diǎn)。我們要從register方法說起。

public void register(Object subscriber) {register(subscriber, defaultMethodName, ThreadMode.PostThread);}public void register(Object subscriber, String methodName, ThreadMode threadMode) {List<Method> subscriberMethods = findSubscriberMethods(subscriber.getClass(), methodName);for (Method method : subscriberMethods) {Class<?> eventType = method.getParameterTypes()[0];subscribe(subscriber, method, eventType, threadMode);}}

register(this)方法執(zhí)行時(shí)調(diào)用了register(Object subscriber, String methodName, ThreadMode threadMode),subscriber是Activity,methodName采用了defaultMethodName的值,這個(gè)值在EventBus中定義為:’onEvent’,threadMode為ThreadMode.PostThread。其中ThreadMode為一個(gè)枚舉,它有兩個(gè)值:

public enum ThreadMode {/** Subscriber will be called in the same thread, which is posting the event. */PostThread,/** Subscriber will be called in Android's main thread (sometimes referred to as UI thread). */MainThread,/* BackgroundThread */}

PostThread用于標(biāo)識(shí)發(fā)送線程,MainThread用于標(biāo)識(shí)主線程。它們在后期執(zhí)行的區(qū)別為:如果在注冊時(shí)為PostThread,則事件發(fā)送后,會(huì)直接調(diào)起監(jiān)聽方法。而如果注冊時(shí)為MainThread,則會(huì)經(jīng)過主線程的消息隊(duì)列調(diào)起。

好,回到剛才的地方,在register(Object subscriber, String methodName, ThreadMode threadMode)方法內(nèi)先執(zhí)行了findSubscriberMethods,我們移步看看這個(gè)方法內(nèi)執(zhí)行了什么工作:

private List<Method> findSubscriberMethods(Class<?> subscriberClass, String methodName) {...List<Method> subscriberMethods;...subscriberMethods = new ArrayList<Method>();Class<?> clazz = subscriberClass;HashSet<Class<?>> eventTypesFound = new HashSet<Class<?>>();while (clazz != null) {String name = clazz.getName();...Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {if (method.getName().equals(methodName)) {Class<?>[] parameterTypes = method.getParameterTypes();if (parameterTypes.length == 1) {if (eventTypesFound.add(parameterTypes[0])) {// Only add if not already found in a sub classsubscriberMethods.add(method);}}}}clazz = clazz.getSuperclass();}...}

這里面的代碼比較長,將不必要的略去。這段代碼主要做了以下工作:

根據(jù)給定的類,遍歷該類及其父類所有的方法,如果遍歷時(shí)發(fā)現(xiàn)與給定的方法名相等,并且該方法的參數(shù)只有一個(gè),那么就將該方法加入到subscriberMethods中,最后返回。這里被找到的方法是同名的,但是參數(shù)類型不同,這里的參數(shù)類型決定了將來要監(jiān)聽的事件類型。

好,我們回到findSubscriberMethods之前被調(diào)用的地方,繼續(xù)往下走。接下來的動(dòng)作是將findSubscriberMethods方法返回的Method列表進(jìn)行遍歷。而這次遍歷時(shí),將Method的第一個(gè)參數(shù)類型作為參數(shù)傳給了subscribe方法:

private void subscribe(Object subscriber, Method subscriberMethod, Class<?> eventType, ThreadMode threadMode) {CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions == null) {subscriptions = new CopyOnWriteArrayList<Subscription>();subscriptionsByEventType.put(eventType, subscriptions);} ...subscriberMethod.setAccessible(true);Subscription subscription = new Subscription(subscriber, subscriberMethod, threadMode);subscriptions.add(subscription);...}

該方法首先做的就是根據(jù)eventType從subscriptionsByEventType對象中取出對應(yīng)的subscriptions,然這里第一次肯定是null。所以先進(jìn)行實(shí)例化,然后存放于subscriptionsByEventType中。而subscriptionsByEventType對象存放的就是根據(jù)eventType所對應(yīng)的subscriptions。而subscriptions中存放的就是所有的觀察者,待會(huì)有時(shí)間發(fā)生時(shí),根據(jù)事件的類型,從subscriptionsByEventType中取出所有的觀察者subscriptions逐一通知。

在創(chuàng)建了觀察者列表subscriptions之后開始創(chuàng)建具體的觀察者。Subscription是一個(gè)基本的類,它的示例只是持有了subscriber(Activity),subscriberMethod(onEvent),threadMode(ThreadMode.PostThread)三者的引用而已。

到這里,觀察者Activity監(jiān)聽某一事件的注冊工作就算完成了。

事件發(fā)送

接下來,我們將從事件發(fā)送入口post方法開始分析:

public void post(Object event) {//這里的兩個(gè)屬性很重要,下面這個(gè)用于緩存事件,待下次事件執(zhí)行時(shí),一并執(zhí)行。List<Object> eventQueue = currentThreadEventQueue.get();eventQueue.add(event);//這個(gè)用于標(biāo)識(shí)是否正在發(fā)送事件,保證事件的順序發(fā)送。防止多線程情況下的交叉執(zhí)行。BooleanWrapper isPosting = currentThreadIsPosting.get();if (isPosting.value) {return;} else {isPosting.value = true;try {while (!eventQueue.isEmpty()) {postSingleEvent(eventQueue.remove(0));}} finally {isPosting.value = false;}}}

這里最開始有兩個(gè)EventBus的成員屬性,這里很重要:currentThreadEventQueue與currentThreadIsPosting。這兩個(gè)屬性本身是和線程有關(guān)系的。關(guān)于這兩個(gè)屬性內(nèi)部的作用機(jī)制這里就不再贅述了。上面post方法的第一行currentThreadEventQueue.get()返回的是一個(gè)空的ArrayList()對象。而currentThreadIsPosting.get()方法返回的是一個(gè)BooleanWrapper對象,它的默認(rèn)屬性value默認(rèn)是false。如果對這塊的返回值有疑問,可以在EventBus.java文件內(nèi)找到這兩個(gè)對象的定義,它們在new時(shí),通過initialValue方法返回了get獲取到的初始值。

通過判斷,最終進(jìn)入postSingleEvent方法內(nèi),而該方法則是事件分發(fā)的核心:

private void postSingleEvent(Object event) throws Error {List<Class<?>> eventTypes = findEventTypes(event.getClass());...int countTypes = eventTypes.size();for (int h = 0; h < countTypes; h++) {Class<?> clazz = eventTypes.get(h);CopyOnWriteArrayList<Subscription> subscriptions;synchronized (this) {subscriptions = subscriptionsByEventType.get(clazz);}if (subscriptions != null) {for (Subscription subscription : subscriptions) {if (subscription.threadMode == ThreadMode.PostThread) {postToSubscribtion(subscription, event);} else if (subscription.threadMode == ThreadMode.MainThread) {mainThreadPoster.enqueue(event, subscription);} else {throw new IllegalStateException("Unknown thread mode: " + subscription.threadMode);}}...}}...}

這個(gè)方法內(nèi)首先調(diào)用了findEventTypes方法,我們先移步看看它做了什么工作:

private List<Class<?>> findEventTypes(Class<?> eventClass) {...Class<?> clazz = eventClass;while (clazz != null) {eventTypes.add(clazz);addInterfaces(eventTypes, clazz.getInterfaces());clazz = clazz.getSuperclass();}return eventTypes;}

這部分的主要工作為:將指定類以及父類所實(shí)現(xiàn)的接口及其本身的類型加入到eventTypes中,最后將eventTypes返回。如果我們在定義事件類型時(shí),沒有繼承任何類、實(shí)現(xiàn)任何接口,那么就會(huì)省去這個(gè)步驟,節(jié)省時(shí)間。

回到postSingleEvent方法繼續(xù)往下看:根據(jù)剛剛返回的事件類型集合開始遍歷,每次遍歷時(shí),根據(jù)給定的事件類型從subscriptionsByEventType中尋找對應(yīng)的監(jiān)聽者。我們在上面分析注冊部分時(shí)候已經(jīng)見過,subscriptionsByEventType中存放的就是事件類型與監(jiān)聽者的鍵值對。找到監(jiān)聽者列表subscriptions之后,開始對subscriptions進(jìn)行遍歷,進(jìn)行消息下發(fā)。

消息的發(fā)送主要兩種模式:

  • PostThread
  • MainThread

我們在開頭的時(shí)候就提到過,PostThread會(huì)通過反射直接調(diào)起對應(yīng)的方法,而MainThread則會(huì)通過主線程的消息隊(duì)列進(jìn)行調(diào)起。我們來看看究竟是不是這樣:

//PostThread的執(zhí)行方式static void postToSubscribtion(Subscription subscription, Object event) throws Error {...subscription.method.invoke(subscription.subscriber, event);...}//MainThread的執(zhí)行方式void enqueue(Object event, Subscription subscription) {PendingPost pendingPost = PendingPost.obtainPendingPost(event, subscription);Message message = obtainMessage();message.obj = pendingPost;if (!sendMessage(message)) {throw new RuntimeException("Could not send handler message");}}

可以看到:對于PostThread類型,直接通過反射將事件傳給了觀察者。而對于MainThread類型,則是通過Handler將信息傳給了主線程。最后消息到達(dá)主線程后,通過與PostThread方式一樣經(jīng)過postToSubscribtion方法執(zhí)行。


以上就是關(guān)于EventBus事件監(jiān)聽注冊、事件廣播的解析過程。

總結(jié)

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

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

主站蜘蛛池模板: 国产www网站| 亚洲干 | av黄色免费观看 | 欧美午夜精品一区二区三区电影 | 国产精品成人aaaa在线 | 中文在线а√在线 | 一级片免费网址 | 热@国产 | 日韩在线不卡视频 | 自拍视频网址 | 青青毛片 | 九七久久| 女同av在线 | 美女脱裤子让男人捅 | 91嫩草视频在线观看 | 无遮挡的裸体按摩的视频 | 天天操天天操天天射 | 自拍偷拍第八页 | 国产奶头好大揉着好爽视频 | 波多野结衣中文字幕在线播放 | av黄色在线观看 | 日批网站在线观看 | 亚洲综合一二三区 | 制服诱惑一区二区 | 玖玖久久| 国产无遮挡a片又黄又爽 | 国产精品探花视频 | 2024av视频 | 日本少妇毛茸茸高潮 | 亚洲精品日韩在线 | 午夜精品影院 | 蜜桃av网站 | 日韩精品一区二区三区av | 五月婷婷六月丁香综合 | 日韩日韩日韩日韩日韩 | 无码专区久久综合久中文字幕 | 色丁香久久 | av鲁丝一区二区鲁丝 | a天堂视频 | www.色妞| 韩国精品一区二区 | 色呦呦网站 | 中文字幕欧美色图 | 欧美囗交做爰视频 | 国产伦精品一区二区三区视频免费 | 国产男男gay体育生网站 | 成人小视频在线观看 | 国产精品xx | 午夜插插| 日本在线免费观看 | 国产成人短视频 | 五月天精品视频 | 无码人妻aⅴ一区二区三区有奶水 | 日本啪啪片 | 一级bbbbbbbbb毛片 | 亚洲自拍p | 免费黄色小视频在线观看 | 又大又粗欧美黑人aaaaa片 | 青青草视频免费观看 | 成人精品亚洲 | 欧美视频一区二区 | 精品人妻一区二区三区香蕉 | 网站免费视频www | 狠狠干快播 | 99在线视频播放 | 精品人妻一区二区三 | 亚洲成人一区在线观看 | 九九热视频免费 | 99福利影院 | 久久综合爱| 亚洲成人自拍网 | 中文字幕第一页亚洲 | 俄罗斯厕所偷拍 | 九九热视频在线播放 | 朝桐光一区二区三区 | 日本一二三区不卡 | 综合色伊人 | 久久久久人妻精品色欧美 | 午夜日韩电影 | 无遮挡又爽又刺激的视频 | 日韩欧美一 | 毛片网站网址 | 福利影院av | 天天操,夜夜操 | 欧美男女视频 | 欧美成人三级伦在线观看 | 日韩午夜在线视频 | 亚洲成人激情在线 | 国产精品久久久久久av | 特级黄色网 | 内射中出日韩无国产剧情 | 婷婷国产一区 | 国内偷拍第一页 | 日本va欧美va精品发布 | 激情五月婷婷综合网 | 亚洲精品视频一区 | 国产黄色免费大片 | 日本午夜精品 | 九一av |