活兒好又不糾纏的 IntentService

版權聲明:android

本帳號發佈文章均來自公衆號,承香墨影(cxmyDev),版權歸承香墨影全部。多線程

未經容許,不得轉載。oop

1、前言

Service 是 Android 四大組件之一,正常來講,咱們直接使用 Service 就能夠了。ui

可是 Service 存在幾個問題:this

  1. 默認不會運行在單獨的進程中,而是和所在應用共用同一個進程。
  2. Service 也是在主線程中運行,因此一些耗時操做,依然須要單獨開啓線程去執行。

第一個問題其實並非什麼大的問題,可是正常來講,咱們使用 Service 就是想在後臺執行一些其餘的操做,例如:下載等,而這些,又須要額外開啓線程來完成任務,這樣無形之中加大了咱們的代碼量。線程

而 IntentService 就是爲這個而生的。設計

2、什麼是IntentService

IntentService 是繼承自 Service 的,因此它本質上仍是一個 Service 。在 IntentService 內部維護了一個 WorkerThread 來專門處理耗時操做,實際上它會將全部 IntentService 的業務操做都放在 WorkerThread 中執行。3d

若是 start 了屢次相同的 IntentService ,那麼每一次 start 的任務,都會在 WorkerThread 中依次執行。而最讓咱們省心的是,IntentService 在執行完這些任務以後,會調用 stopSelf() 結束本身。code

從官方文檔能夠了解到,一些 IntentService 的特色:cdn

  1. 它會建立獨立的 WorkerThread 來處理全部的 Intent 請求。
  2. 它會建立獨立的 WorkerThread 來處理 onHandleIntent() 的實現代碼,無需擔憂多線程的問題。
  3. 全部請求完成以後,IntentService 會自動中止。
  4. 它的 onBind() 默認返回 null,不要去實現它,不要用 bindService() 綁定一個 IntentService。
  5. 它的 onStartCommand() 提供了默認的實現,會將請求的 Intent 添加到隊列中。

從上面的介紹能夠了解到,在 IntentService 開啓了一個獨立的 WorkerThread 來完成具體任務的執行,而咱們只須要將須要完成的業務代碼,在 onHandleIntent() 中實現便可。

3、如何使用 IntentService

既然已經對 IntentService 有一個簡單的認識了,那麼接下來就實現一個最簡單的 IntentService 的 Demo。

IntentService 自己已經幫咱們實現了大部分邏輯,咱們只須要在 onHandleIntent() 中實現咱們的業務邏輯代碼便可。

Demo 中給的例子,其實什麼也沒作,就是 Thread.sleep() 了一會,而後輸出了一些 Log。這樣就完成了一個最簡單的 IntentService 。

IntentService 使用起來也很是的簡單,只須要經過構造方法傳遞 String 類型的參數,用於指定 WorkerThread 的名字,而後和日常使用 Service 同樣調用 startService() 便可。
startService(new Intent(MainActivity.this,MyIntentService.class));

IntentService 依然仍是一個 Service,因此須要在 AndroidManifest.xml 中爲它註冊。

<service android:name=".MyIntentService"/>

這裏快速對 MyIntentService 調用三次 startService(),咱們來看看輸出的結果。

能夠看到,每次 startService 的 startId 都不相同,而 IntentService 每次執行完成當前任務以後,會根據 startId 調用 stopSelf() 方法來標記須要中止服務,當最終沒有須要執行的任務的時候,纔會 onDestory() 銷燬本身。這個細節,下一小結會詳細講解。

3、IntentService 如何實現它的特性

既然已經瞭解了 IntentService 的特性和如何使用它,接下來不看看具體它是如何實現的,總感受缺乏點什麼。

那麼咱們就來從源碼的角度,看看它是如何實現的。自己整個類,也只有不到二百行代碼,真實有效的代碼也就那麼十幾行,很是好理解。

先來看看 IntentService 是如何爲一個 WorkerThread 的。

能夠看到它其實是使用了一個 HandlerThread 來維護線程的,而在 HandleThread 中,內部已經維護一個 Looper,這裏直接使用 HandlerThread 的 Looper 對象,便於在 IntentService 中去維護消息隊列,而這裏最終建立的 mServiceHandler 是屬於 HandleThread 這個 WorkerThread 的。

而在 ServiceHandler 中,直接轉發 Message 中攜帶的 Intent 對象,給 onHandleIntent() 方法去執行具體的業務邏輯。執行完成以後,當即調用 stopSelf() 方法中止本身,注意這裏 stopSelf() 方法的參數是 arg1。

接下來看看當咱們調用 startService() 的時候,IntentService 到底幹了什麼?

onStartCommand() 中直接調用了 onStart() 方法,而上面 stopSelf() 方法使用的 arg1 正是這個 Service 的 startId,也就是說,它是會指定 startId 來中止當前的這次任務服務。而 Service 若是被啓動屢次,就會存在多個 startId ,當全部的 startId 都被中止以後,纔會調用 onDestory() 自我銷燬。這也解釋了爲何屢次 start 同一個 IntentService 它會順序執行,所有執行完成以後,再自我銷燬。

最終會在 onDestory() 中調用 quit 去退出 Looper 的循環,釋放資源。

4、查缺補漏

自己 IntentService 適用的場景,就是一種無狀態的 Service,因此它是不支持 bindService() 方法去 bound 一個服務的。正如它的 onBind() 實現,直接返回一個 null。

固然若是你強制想要使用 bindService() 去實現 onBind() 方法,也是能夠的,比較 IntentService 自己也是一個 Service,可是這樣就不符合 IntentService 的設計規範,破壞了它使用完成以後自我銷燬的理念,這個時候仍是推薦使用正常的 Service 便可。

而若是確實有完成以後交互的需求,能夠考慮使用 EventBus 或者 LocalBroadcastManager 這種通訊的方式來傳遞數據,都是一種不錯的方案。

公衆號二維碼.jpg
相關文章
相關標籤/搜索