玩轉EventBus,詳解其使用

2022-01-01 非著名程式設計師

【回復「1024」,送你一個特別推送】


概述

EventBus是一款針對Android優化的發布/訂閱(publish/subscribe)事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息。簡化了應用程式內各組件間、組件與後臺線程間的通信。優點是開銷小,代碼更優雅。以及將發送者和接收者解耦。比如請求網絡,等網絡返回時通過Handler或Broadcast通知UI,兩個Fragment之間需要通過Listener通信,這些需求都可以通過EventBus實現。

EventBus作為一個消息總線,有三個主要的元素:

Event:事件。可以是任意類型的對象

Subscriber:事件訂閱者,接收特定的事件。在EventBus中,使用約定來指定事件訂閱者以簡化使用。即所有事件訂閱都都是以onEvent開頭的函數,具體來說,函數的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync這四個,這個和ThreadMode(下面講)有關。

Publisher:事件發布者,用於通知 Subscriber 有事件發生。可以在任意線程任意位置發送事件,直接調用eventBus.post(Object) 方法,可以自己實例化 EventBus 對象,但一般使用默認的單例就好了:EventBus.getDefault(), 根據post函數參數的類型,會自動調用訂閱相應類型事件的函數。


關於ThreadMode

前面說了,Subscriber的函數只能是那4個,因為每個事件訂閱函數都是和一個ThreadMode相關聯的,ThreadMode指定了會調用的函數。有以下四個ThreadMode:

PostThread:事件的處理在和事件的發送在相同的進程,所以事件處理時間不應太長,不然影響事件的發送線程,而這個線程可能是UI線程。對應的函數名是onEvent。

MainThread: 事件的處理會在UI線程中執行。事件處理時間不能太長,這個不用說的,長了會ANR的,對應的函數名是onEventMainThread。

BackgroundThread:事件的處理會在一個後臺線程中執行,對應的函數名是onEventBackgroundThread,雖然名字是BackgroundThread,事件處理是在後臺線程,但事件處理時間還是不應該太長,因為如果發送事件的線程是後臺線程,會直接執行事件,如果當前線程是UI線程,事件會被加到一個隊列中,由一個線程依次處理這些事件,如果某個事件處理時間太長,會阻塞後面的事件的派發或處理。

Async:事件處理會在單獨的線程中執行,主要用於在後臺線程中執行耗時操作,每個事件會開啟一個線程(有線程池),但最好限制線程的數目。

根據事件訂閱都函數名稱的不同,會使用不同的ThreadMode,比如果在後臺線程加載了數據想在UI線程顯示,訂閱者只需把函數命名onEventMainThread。


對相應的函數名,進一步解釋一下:

onEvent:如果使用onEvent作為訂閱函數,那麼該事件在哪個線程發布出來的,onEvent就會在這個線程中運行,也就是說發布事件和接收事件線程在同一個線程。使用這個方法時,在onEvent方法中不能執行耗時操作,如果執行耗時操作容易導致事件分發延遲。

onEventMainThread:如果使用onEventMainThread作為訂閱函數,那麼不論事件是在哪個線程中發布出來的,onEventMainThread都會在UI線程中執行,接收事件就會在UI線程中運行,這個在Android中是非常有用的,因為在Android中只能在UI線程中跟新UI,所以在onEvnetMainThread方法中是不能執行耗時操作的。

onEventBackground:如果使用onEventBackgrond作為訂閱函數,那麼如果事件是在UI線程中發布出來的,那麼onEventBackground就會在子線程中運行,如果事件本來就是子線程中發布出來的,那麼onEventBackground函數直接在該子線程中執行。

onEventAsync:使用這個函數作為訂閱函數,那麼無論事件在哪個線程發布,都會創建新的子線程在執行onEventAsync。

基本用法

引入EventBus:

compile 'org.greenrobot:eventbus:3.0.0'

定義事件:

public class MessageEvent { /* Additional fields if needed */ }

註冊事件接收者:

eventBus.register(this);

發送事件:

eventBus.post(event)

接收消息並處理:

public void onEvent(MessageEvent event) {}

註銷事件接收:

eventBus.unregister(this);

最後,proguard 需要做一些額外處理:

#EventBus -keepclassmembers class ** {    public void onEvent*(**);    void onEvent*(**); }

實戰舉例


關於Activity之間的通信

第一步:自定義一個定義Event事件,用來封裝信息
例子如下:

public class UserEvent {    private String userName;    public UserEvent() {    }    public UserEvent(String userName) {        this.userName = userName;    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }}

第二步:註冊訂閱者和定義處理方法

public class MainActivity extends Activity {    private Button btn, fragment_btn;    private TextView service_tv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //註冊訂閱者        EventBus.getDefault().register(this);        btn = (Button) findViewById(R.id.btn);        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                // TODO Auto-generated method stub                Intent intent = new Intent(MainActivity.this,                        SecondActivity.class);                startActivity(intent);            }        });        fragment_btn = (Button) findViewById(R.id.fragment_btn);        fragment_btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent(MainActivity.this,                        FragmenTestActivity.class);                startActivity(intent);            }        });        service_tv = (TextView) findViewById(R.id.service_tv);        startService(new Intent(this, EventTestService.class));    }    //定義處理接收方法    @Subscribe    public void onEventMainThread(UserEvent event) {        btn.setText(event.getUserName());        service_tv.setText(event.getUserName());    }    @Override    protected void onDestroy() {        super.onDestroy();        EventBus.getDefault().unregister(this);    }}

第三步:發送事件

public class SecondActivity extends Activity {    private Button btn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        btn = (Button) findViewById(R.id.btn);        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                final UserEvent ue = new UserEvent();                ue.setUserName("非著名程式設計師");                EventBus.getDefault().post(ue);                finish();            }        });    }}

fragment,service等之間的通信和activity之間的基本一樣,就不過多的貼代碼解釋了,感興趣的同學可以直接下載demo,裡面有它們之間的通信。

使用EventBus應該注意以下幾點:

同一個onEvent函數不能被註冊兩次,所以不能在一個類中註冊同時還在父類中註冊。

消息的接收是根據參數中的類名來決定執行哪一個接收處理方法的。即:訂閱者的處理方法是根據訂閱事件的類型來確定訂閱函數的。

每個事件可以有多個訂閱者。

當Post一個事件時,這個事件類的父類的事件也會被Post。

所有事件處理方法必需是public void類型的,並且只有一個參數表示EventType。

在這裡我把demo分享出去,demo裡包含了Activity之間的通信,fragment之間的通信和service與activity之間的通信。

下載地址:http://7xsgef.com1.z0.glb.clouddn.com/EventBusDemo2.zip

相關焦點

  • EventBus源碼詳解(一)
    粘性事件可以當作普通事件使用。new SubscriberMethodInfo("onLowPriorityEvent", com.leo.eventbus.sample2.PriorityEvent.class),11            new SubscriberMethodInfo("onHighPriorityEvent", com.leo.eventbus.sample2.PriorityEvent.class
  • EventBus 原理深度解析
    如果是同一個jvm裡面通知的話,就可以使用EventBus。由於EventBus使用起來簡單、便捷,因此,工作中會經常用到。深入理解該框架的原理就很有必要。二、框架解析2.1、組織結構eventbus的組織結構如下:
  • Vue組件的通信--eventBus
    但是對於具有簡單體系結構的應用程式來說,使用事件在組件之間進行通信就足夠了。為此,我們可以創建一個快速的解決方案並實現EventBus,也稱作vue的中央事件總線,適用於跨級或兄弟組件。EventBus允許我們在一個組件中發出一個事件,而在另一個組件中偵聽該事件。本示例將說明如何在Vue.js應用程式中執行此操作。
  • Android EventBus3 源碼解析 把控事件總線
    使用:1.1 項目引入EventBus(Gradle)打開對應模塊的build.gradle,在dependencies中加入EventBus依賴:compile 'org.greenrobot:eventbus:3.0.0'EventBus3.0最大的優化就是通過EventBusAnnotationProcessor在編譯時生成索引,
  • EventBus 流程解析
    作者丨老王頭碎碎念https://www.jianshu.com/p/c64b2315db3cEventBus 源碼解析先介紹控制項使用方法
  • 你不可不知的前端進階知識:Vue事件總線(EventBus)使用詳細介紹
    首先需要創建事件總線並將其導出,以便其它模塊可以使用或者監聽它。我們可以通過兩種方式來處理。先來看第一種,新創建一個 .js 文件,比如 event-bus.js實質上EventBus是一個不具備DOM的組件,它具有的僅僅只是它實例方法而已,
  • 面試題之---EventBus源碼解析
    方法: 子類調用父類的某個方法給父類某個屬性賦值  另外一個子類通過父類的另一個公有方法獲取這個值(這個方法把值返回)(二)基本使用先訂閱,後發布    compile 'org.greenrobot:eventbus:3.1.1'public class MessageEvent {    private
  • EventBus 3.0+ 源碼詳解(史上最詳細圖文講解)(上)
    本文講解的是 'org.greenrobot:eventbus:3.1.1' 最新版,和其他版本有細微差別,思想都是一樣的。這樣設計的目: EventBus 在代碼使用過程中不僅僅只有一條總線,還有其他的訂閱總線,訂閱者可以註冊到不同的 EventBus 總線,然後通過不同的 EventBus 總線發送數據。
  • EventBus—事件總線
    $on('event1', cb1);vm.$on('event1', cb2);vm.$on('event1', cb3);則此時vm._events={event1: [cb1, cb2, cb3]}當調用移除監聽事件的方法時,所做的操作為移除其對應數組裡的回調函數,例如當我們調用vm.
  • EventBus3.0 使用及源碼解析
    使用EventBus之後,這些將不再是問題。盜用GiHub上EventBus的一張圖。註解Subscribe在運行時解析,且只能加在METHOD上。看到這裡差不多可以鬆口氣,終於要分發調用訂閱者的訂閱事件了!
  • 事件總線(Event Bus)知多少
    發送郵件事件:起因是用戶使用郵箱註冊成功需要驗證郵箱,經過是郵件發送,結果是郵件是否發送成功。其實這六要素也適用於我們程序中事件的處理過程。但很顯然這個代碼實現僅適用於當前這個釣魚場景,假如有其他場景也想使用這個模式,我們還需要重新定義委託,重新定義事件處理,豈不很累。本著」Don't repeat yourself「的原則,我們要對其進行重構。結合我們對事件本質的探討,事件是由事件源和事件處理組成。
  • vue中的eventBus會產生內存洩漏嗎
    引入本文介紹了eventBus的實現原理,並介紹它如何在vue中使用,並舉了一個具體的例子來說明,如果使用不當,它會造成內存洩漏。fr=aladdin內容在vue使用eventBus;使用不當的問題:多次執行回調;內存洩漏;解決方案
  • .NET編程之事件總線(Event Bus)知多少 (2)
    如果我們只是簡單學習了解事件總線,使用反射無可厚非。但如果在實際的項目中,使用反射卻不是一個很明智的行為,因為其性能問題。尤其是事件總線要集中處理整個應用程式的所有事件,更易導致程序性能瓶頸。既然說到了反射性能,那就順便解釋下為什麼反射性能差?
  • 《玩轉機車儀表》杜卡迪MTS950功能詳解
    杜卡迪 Multistrada 950儀表功能詳解  隨著摩託車技術的日新月異,越來越多的電子輔助系統也進入了摩託車的配置單中,與此同時,與駕駛員交互最為頻繁的摩託車儀表,則成為了這些功能的集中展示和使用區域。
  • Node.js 的 EventEmitter 事件處理詳解
    學完後你將了解事件、怎樣使用  EvenEmitter 以及如何在程序中利用事件。另外還會學習 EventEmitter 類從其他本地模塊擴展的內容,並通過一些例子了解背後的原理。本文涵蓋了關於 EventEmitter 類的所有內容。什麼是事件?
  • JS事件對象Event詳解
    ,例如說 event.target 表示觸發事件的元素,在 IE 中需要使用 event.srcElement 獲取;二、 Event 屬性我們在前面提到,根據觸發方式的不同 event 對象會具有不同的屬性,我們可以將其大體分為幾部分:通用屬性 (無論是通過鍵盤還是滑鼠觸發都擁有的屬性)默認行為指的是瀏覽器中規定的一些行為,比如 <a> 標籤點擊後會跳轉連結
  • 資料|《 21 個項目玩轉深度學習——基於TensorFlow 的實踐詳解 》
    資料 |《 21 個項目玩轉深度學習——基於TensorFlow 的實踐詳解 》
  • Free bus service for Expo visitors
    Visitors will be able to find a shuttle bus station every 300 meters within the 5.28-square-kilometer Expo site, and buses will roll by every three minutes, Huang Jianzhi, deputy director of the
  • 到底是in a bus 還是 on a bus?
    看到標題是不是很熟悉,沒錯!
  • 搞懂事件的使用,詳細解讀Solidity事件Event
    就是以EVM日誌基礎設備提供一個接口,當被事件調用時,出發參數存儲到日誌中,其與合約地址關聯,並記錄到區塊鏈中。關係就是:區塊鏈是打包交易區塊組成的鏈條,每一個交易會包含0到多個記錄,日誌代表智能合約所觸發事件。DAPP中,監聽了事件,當事件發生時,會回調。