項目中遇到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 的粘性事件來解決。