項目中遇到activity傳大資料集合。使用EventBus滞後傳統的功能。網上找到的阿裡開發手冊的内容 。記錄筆記。
阿裡給出的方案,是通過 EventBus 來傳遞資料。
EventBus 的 粘性事件
很多商業項目其實都用到了 EventBus,這裡就簡單介紹如何使用 EventBus 的粘性事件來完成資料在 Activity 間的傳遞。
EventBus 是一個 Android 端優化的 Publish/subscribe 消息總線,簡化了應用程式内各個元件間、元件與背景線程間的通信。
在 Activity 中使用 EventBus,需要根據 Activity 的生命周期,成對調用 register() 和 unregister() 方法。普通的事件,隻會發生在 register() 之後,在注冊前發生的事件,統統都收不到。
這裡利用的 EventBus 的粘性事件(Sticky Event)來實作,EventBus 内部維護了一個 Map 對象 stickyEvents,用于緩存粘性事件。
粘性事件使用 postSticky() 方法發送,它會将事件緩存到 stickyEvents 這個 Map 對象中,以待下次注冊時,将這個事件取出,抛給注冊的元件。以此來達到一個粘性的滞後事件發送和接收。
接下來我們看看 EventBus 粘性事件的使用細節。
1. 注解的差別
粘性事件的注解和普通事件的注解略有差別,需要添加 threadMode 和 sticky 參數。
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
publicvoidonStickyEvent(MyStickyEvent event){
//...
}
注意,這兩個額外的參數是必須的。
2. 調用方法的差別
在發送消息的時候,需要使用 postSticky() 來替換掉 post() 方法。
需要注意的是,粘性事件是使用 Map 結構緩存的,并且是使用事件對象類型當 Key 進行緩存,是以對于同類型的資料,它隻會緩存最後發送的資料。
3. 注意清理事件
前面也提到,粘性事件是存儲在一個 Map 對象中的,它是不會主動清理其中存儲的對象的,需要開發者手動清理。
EventBus 提供了兩類方法 removeStickyEvent() 和 removeAllStickyEvents() 方法,分别用來清理固定資料以及全部資料。
我們需要在合适的時機,手動的調用這兩類方法,清理粘性事件。如果不對粘性事件進行清理,每次 register() 的時候,都會收到粘性事件。
4. EventBus 粘性事件的問題
粘性事件本身是脫離了 Android Intent 資料傳遞的這一套機制的,要知道 Activity 會在一些特殊情況下被銷毀重建,在此情況下,通過 Intent 傳遞的資料,是可以繼續從 Intent 中擷取恢複到上一次頁面傳遞的資料。
而通過 EventBus 的粘性事件,則可能在銷毀重建時,造成資料丢失。
如果想要使用 EventBus 的粘性事件,來在頁面間傳遞大資料,還是有不少細節,需要根據業務來調整的。
四、小結時刻
今天我們聊到了在 Activity 間,通過 Intent 傳遞大資料會觸發 TransactionTooLargeException 異常的原因,以及如何解決它,最後再簡單總結一下。
- Intent 無法傳遞大資料是因為其内部使用了 Binder 通信機制,Binder 事務緩沖區限制了傳遞資料的大小。
- Binder 事務緩沖區的大小限定在 1MB,但是這個尺寸是共享的,也就是并不是傳遞 1MB 以下的資料就絕對安全,要視目前的環境而定。
- 不要挑戰 Intent 傳遞資料大小的極限,對于大資料,例如長字元串、Bitmap 等,不要考慮 Intent 傳遞資料的方案。
- 解決大資料傳遞問題,可以從資料源出發,根據資料的辨別,還原資料,或者先持久化再還原。也可以使用 EventBus 的粘性事件來解決。