国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 中 EventBus 的使用之多線程事件處理

2020-04-11 11:16:43
字體:
來源:轉載
供稿:網友

在這一系列教程的最后一篇中,我想談談GR的EventBus,在處理多線程異步任務時是多么簡單而有效。

AsyncTask, Loader和Executor…… 拜托!

Android中有很多種執行異步操作的方法(指平行于UI線程的)。AsyncTask對于用戶來說是最簡單的一種機制,并且只需要少量的設置代碼即可。然而,它的使用是有局限的,正如Android官方文檔中所描述的:

AsyncTask被設計成為一個工具類,在它內部包含了Thread和Handler,但它本身并不是通用線程框架的一部分。AsyncTask應該盡可能地被用在執行一些較短的操作中(最多幾秒)。如果你需要在線程中執行較長時間的任務,那么建議你直接使用java.util.concurrent包中提供的各種API,如Executor、 ThreadPoolExecutor以及FutureTask。

不過即便是執行短時間的操作也會帶來一些問題,特別是在與Activity/Fragment生命周期有關的地方。由于AsyncTask會持續地運行下去(即使啟動它們的Activity/Fragment已經被銷毀了)。這樣,一旦你在onPostExecute方法中試圖對UI進行更新,那么最終將導致拋出一個IllegalStateException異常。

Android 3.0中引入了Loader API用來解決Activity/Fragment生命周期的問題(它們的確很有效)。Loader API被設計成向Activity/Fragment中以異步方式加載數據。盡管加載數據是一種非常常見的異步操作,但并非唯一一種需要從UI線程中分開的操作。Loader還需要在Activity/Fragment中實現另外一個監聽接口。盡管這么做沒有錯,但我個人并不喜歡這種模式(我的意思是最終你的代碼中會包含許多的回調函數,導致代碼的可讀性變得很差)。最后,Activity和Fragment也并非唯一需要對異步操作分線程的地方。例如如果在Service里,你就不能訪問LoaderManager,所以最終你還是得使用AsyncTask或者java.util.concurrent。

java.util.concurrent包很不錯,我在Android和非Android項目中都可以使用。不過使用時需要對其進行多一點兒配置和管理,不象AsyncTask那么簡單。你需要對ExecutorService進行初始化,管理和監視它的生命周期,并且可能需要跟一些Future對象打交道。

只要使用恰當,AsyncTask、 Loader和Executor都是非常有效的。但在復雜應用中,需要為每個任務選擇合適的工具,最終你可能三種都會用到。這樣你就得維護三種不同的處理并發的框架代碼。

Green Robot來幫忙了!

GR的EventBus中內置了一個非常棒的并發處理機制。在監聽類中,你可以實現4種不同類型的處理方法。當一個匹配事件被發送過來時,EventBus會根據不同的并發模型將事件發送到相應的處理方法中:

onEvent(T event):運行在和被發送事件相同的線程中。
onEventMainThread(T event):運行在主(UI)線程中,不管事件從哪個線程中被發送過來。
onEventAsync(T event):運行在單獨的線程中,即非UI線程,也非發送事件的線程。
onEventBackgroundThread(T event):如果發送事件的線程不是UI線程,則運行在該線程中。如果發送事件的是UI線程,則它運行在由EventBus維護的一個單獨的線程中。多個事件會同步地被這個單獨的后臺線程所處理。

這些方法功能強大而且使用簡單。例如有一個比較耗時的操作(可能是網絡調用,大量數據處理等),這一操作需要由UI上的行為來觸發,并且當操作執行完畢后還需對UI進行更新。在這個例子中,UI行為即按鈕點擊,按鈕在activity中,耗時操作在service中。我們可以按下面的方式來實現:

Java

盡管這個例子比較簡單,但它卻非常簡明扼要地說明了問題。這里即不需要實現監聽接口,也不會出現類似生命周期之類的問題(由于activity只能在它存在的時候才能接收到OperationCompleteEvent事件)。除此之外,如果發生了配置改變(旋轉屏幕)或其他什么原因導致activity在兩次事件發生之間被銷毀并重建,最終仍可以接收到OperationCompleteEvent事件。

此外,我們也可以容易地想到一些其它用法。比如,如果需要將更新進度發出去,你只需另外實現一個封裝了進度值的事件類,然后將其發送出去即可。或者,如果你想讓其它一些事件(不管是相同還是不同類型)不被并行處理(同步執行),你可以選擇使用onEventBackgroundThread。

依賴Bus

實例化EventBus最簡單的方法就是通過EventBus.getDefault()。然而,在EventBusBuilder類(通過EventBus.builder()獲得)中還包含了另外一些有用的配置方法。特別是在本文中提到過的使用你自己的ExecutorService。缺省情況下EventBus通過Executors.newCachedThreadPool()創建自己的ExecutorService,在大多數情況下都已滿足你的需要。然而,有時你可能仍然想要顯示地控制EventBus所使用的線程數量,這種情況下你就可以象下面這樣初始化EventBus:

Java

EventBus.builder().executorService(Executors.newFixedTheadPool(NUM_THREADS)).installDefaultEventBus();

在EventBusBuilder中另外一些可供配置的是一些和異常處理的有關的控制,以及一個是否允許事件類被繼承的控制開關。這些內容超出了本文所討論的范圍,但我還是建議你仔細去研究一番。GR可能并沒有把這些內容都寫在文檔里,但如果你讀一讀EventBusBuilder和EventBus的源代碼,相信你會很容易理解它們的。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 太保市| 天台县| 苏尼特左旗| 锡林浩特市| 米林县| 邹平县| 吴桥县| 凤冈县| 桑日县| 聊城市| 永安市| 织金县| 博罗县| 阳东县| 当涂县| 莒南县| 嘉定区| 武山县| 军事| 中牟县| 和顺县| 高雄市| 武汉市| 台北县| 清水河县| 乐至县| 南平市| 留坝县| 乐安县| 攀枝花市| 江津市| 从化市| 望城县| 鄂尔多斯市| 军事| 南丰县| 微山县| 宁晋县| 荆门市| 南昌市| 柳河县|