EventBus原理與實(shí)現(xiàn)

分析一個(gè)開源項(xiàng)目的源碼铆帽,首先先從使用的入口開始氯檐,然后Debug或者點(diǎn)點(diǎn)點(diǎn)即可蜕窿。很多時(shí)候源碼并不難, 只是被很多人分析難了氮采,就像我有時(shí)候?qū)憱|西僅僅令自己看一樣殷绍,有時(shí)候只是寫代碼片段,所以最好的學(xué)習(xí)方式還是直接看源碼鹊漠。

EventBus的源碼很簡單主到,總結(jié)一下,能夠在不同組件Activity等等通信的原理即 一個(gè)static的單例對象躯概,成員變量是一個(gè)List等容器==>
注冊時(shí) 用來存放觀察者(List.add)
發(fā)送時(shí) 用來通知觀察者

List list = EventBus靜態(tài)對象.getList();
for(Object o:list){
      EventBus靜態(tài)對象.notify(o);

}

總之登钥,能夠通信就是因?yàn)檫@個(gè)static的對象在自己調(diào)用自己的方法或成員等等.....

**下面是EventBus的用法和原理詳解 **

對于代碼能力理解比較好的可以直接看源碼,當(dāng)然這里也要一個(gè)我改寫過的EventBus版本娶靡,針對原有版本做了簡化牧牢,去除了注解方式,因?yàn)槲腋杏X注解完全是多余的一項(xiàng)姿锭,僅僅使用方便了一些而已塔鳍,卻帶來了理解上的難度和效率的低下
項(xiàng)目地址 https://github.com/wangli0/EventBus
其中tag v0.1是最原始的觀察者模式,此庫完全可以替代原有的EventBus

EventBus用法

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);


    }


    public void onclick(View view) {
        Intent intent = new Intent();
        intent.setClass(this, TwoActivity.class);
        startActivity(intent);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                EventBus.getDefault().post(111);
            }
        },3000);

    }
}
public class TwoActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_two);

        EventBus.getDefault().register(this);

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void helloEventBus(Integer message) { //方法名任意呻此,這里的參數(shù)和  EventBus.getDefault().post(111);對應(yīng)即可
        System.out.println("------>"+message);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }


}


總結(jié): EventBus既可以在一個(gè)Activity里面使用轮纫,又可以在兩個(gè)Activity中使用,不管當(dāng)前顯示的是哪個(gè)焚鲜,只要Activity存在掌唾,消息就會發(fā)送成功。好比 EventBus.getDefault().register(this);就是一個(gè)BroadCastReceiver

原理分析

public final class EventType {
    /**
     * 默認(rèn)的tag
     */
    public static final String DEFAULT_TAG = "default_tag";

    /**
     * 參數(shù)類型  即用 @Subscriber標(biāo)注的方法中的方法參數(shù)
     */
    Class<?> paramClass;
    /**
     * 函數(shù)的tag
     */
    public String tag = DEFAULT_TAG;

    public Object event ;
}


EventBus.getDefault().register(this);執(zhí)行流程

EventBus中維護(hù)一個(gè) mMethodHunter對象忿磅,該對象用來查找this即Subscriber的所有標(biāo)有注解的所有方法

SubsciberMethodHunter和EventBus中 的 mSubcriberMap是同一個(gè)對象 糯彬。鍵值對是 key: EventType value:CopyOnWriteArrayList(Subscription)用于保存一個(gè)EventType類型對應(yīng)多個(gè)Subscription,方便EventBus post()時(shí)候能根據(jù)一個(gè) EventType類型葱她,查找該類型對應(yīng)的所有Subscription情连,然后全部執(zhí)行。

注意: Subscription是不區(qū)分觀察者是誰(這句話得意思是,一個(gè)Activity對象中可能有多個(gè)Subscription,另一個(gè)Activity也有多個(gè),但是他們不區(qū)分)览效,即它只根據(jù)EventType去查找所有Subscription

當(dāng)mMethodHunter查找到register(this) 中this類標(biāo)注@Subscriber 的所有方法后却舀,每一個(gè)符合要求的方法都 構(gòu)造一個(gè)EventType類,如下

EventType eventType = new EventType(paramType, annotation.tag());
//paramType是訂閱方法的唯一的參數(shù)

然后锤灿,根據(jù)subscriber對象即this和Method 構(gòu)造一個(gè)Subscription對象

 Subscription newSubscription = new Subscription(subscriber, method);

然后從根據(jù)EventType從 mSubcriberMap中 獲取CopyOnWriteArrayList 挽拔,然后放進(jìn)去(把同類型的事件對應(yīng)->多個(gè)Subscription,如果list還不存在但校,new一個(gè))

注意: 從這里可以看出螃诅,this中可能有多個(gè)@Subscriber注解,那么就會構(gòu)造多個(gè)Subscription對象状囱。且每個(gè)Subscription里面都有一個(gè)真正的subscriper即this

真正執(zhí)行方法的時(shí)候 => 調(diào)用的是Subscription中method成員變量术裸,反射實(shí)現(xiàn)

subscription.targetMethod.invoke(subscription.subscriber.get(), event);

EventBus.getDefault().post事件

EventBus中另一個(gè)比較有意思的成員變量對象就是 Queue了

ThreadLocal<Queue<EventType>> mLocalEvents = new ThreadLocal<Queue<EventType>>() {
        protected Queue<EventType> initialValue() {
            return new ConcurrentLinkedQueue<EventType>();
        };
    };

查看 post方法

public void post(Object event, String tag) {    
        mLocalEvents.get().offer(new EventType(event.getClass(), tag));
        mDispatcher.dispatchEvents(event);
    }

看到這里,發(fā)現(xiàn)EventBus這個(gè)地方的思路和AsynTask有點(diǎn)相似呢亭枷!
獲取Queue然后把當(dāng)前的要發(fā)送的new EventType(event.getClass(), tag)類型放入隊(duì)列中袭艺。
然后獲取事件分發(fā)器分發(fā)事件:
mDispatcher.dispatchEvents(event);

void dispatchEvents(Object aEvent) {
            Queue<EventType> eventsQueue = mLocalEvents.get();
            while (eventsQueue.size() > 0) {  //把Queue中的事件全部發(fā)出去
                deliveryEvent(eventsQueue.poll(), aEvent);
            }
        }
void deliveryEvent(EventType type, Object aEvent) {
            // 如果有緩存則直接從緩存中取
            List<EventType> eventTypes = getMatchedEventTypes(type, aEvent);
            // 迭代所有匹配的事件并且分發(fā)給訂閱者
            for (EventType eventType : eventTypes) {
                handleEvent(eventType, aEvent);
            }
        }

根據(jù)EventType獲取list即 List<Subscription> subscriptions = mSubcriberMap.get(eventType);
然后for循環(huán)執(zhí)行所有 Subscription

  /**
         * 處理單個(gè)事件
         * 
         * @param eventType
         * @param aEvent
         */
        private void handleEvent(EventType eventType, Object aEvent) {
            List<Subscription> subscriptions = mSubcriberMap.get(eventType);
            if (subscriptions == null) {
                return;
            }

            for (Subscription subscription : subscriptions) {
                final ThreadMode mode = subscription.threadMode;
                EventHandler eventHandler = getEventHandler(mode);
                // 處理事件
                eventHandler.handleEvent(subscription, aEvent);
            }
        }

執(zhí)行方法,實(shí)質(zhì)即為調(diào)用反射Method.invoke();

subscription.targetMethod.invoke(subscription.subscriber.get(), event);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叨粘,一起剝皮案震驚了整個(gè)濱河市猾编,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌升敲,老刑警劉巖答倡,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異驴党,居然都是意外死亡瘪撇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門港庄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來倔既,“玉大人,你說我怎么就攤上這事攘轩〔娲妫” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵度帮,是天一觀的道長歼捏。 經(jīng)常有香客問我,道長笨篷,這世上最難降的妖魔是什么瞳秽? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮率翅,結(jié)果婚禮上练俐,老公的妹妹穿的比我還像新娘。我一直安慰自己冕臭,他們只是感情好腺晾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布燕锥。 她就那樣靜靜地躺著,像睡著了一般悯蝉。 火紅的嫁衣襯著肌膚如雪归形。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天鼻由,我揣著相機(jī)與錄音暇榴,去河邊找鬼。 笑死蕉世,一個(gè)胖子當(dāng)著我的面吹牛蔼紧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狠轻,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奸例,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了哈误?” 一聲冷哼從身側(cè)響起哩至,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜜自,沒想到半個(gè)月后菩貌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡重荠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年箭阶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戈鲁。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仇参,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出婆殿,到底是詐尸還是另有隱情诈乒,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布婆芦,位于F島的核電站怕磨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏消约。R本人自食惡果不足惜肠鲫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望或粮。 院中可真熱鬧导饲,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至袋毙,卻和暖如春辈讶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背娄猫。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留生闲,地道東北人媳溺。 一個(gè)月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像碍讯,于是被迫代替她去往敵國和親悬蔽。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 項(xiàng)目到了一定階段會出現(xiàn)一種甜蜜的負(fù)擔(dān):業(yè)務(wù)的不斷發(fā)展與人員的流動性越來越大捉兴,代碼維護(hù)與測試回歸流程越來越繁瑣蝎困。這個(gè)...
    fdacc6a1e764閱讀 3,181評論 0 6
  • 先吐槽一下博客園的MarkDown編輯器,推出的時(shí)候還很高興博客園支持MarkDown了倍啥,試用了下發(fā)現(xiàn)支持不完善就...
    Ten_Minutes閱讀 563評論 0 2
  • 原文鏈接:http://blog.csdn.net/u012810020/article/details/7005...
    tinyjoy閱讀 546評論 1 5
  • EventBus 簡介 EventBus 直譯過來就是事件總線禾乘,熟悉計(jì)算機(jī)原理的人一定很熟悉總線的概念,所有設(shè)備都...
    DanieX閱讀 1,043評論 0 1
  • 博文出處:EventBus源碼解析虽缕,歡迎大家關(guān)注我的博客始藕,謝謝! 0001B 時(shí)近年末氮趋,但是也沒閑著伍派。最近正好在看...
    俞其榮閱讀 1,301評論 1 16