活兒好又不糾纏的 IntentService

承香墨影發表於2017-05-12

版權宣告:

本賬號釋出文章均來自公眾號,承香墨影(cxmyDev),版權歸承香墨影所有。

未經允許,不得轉載。

一、前言

Service 是 Android 四大元件之一,正常來說,我們直接使用 Service 就可以了。

但是 Service 存在幾個問題:

  1. 預設不會執行在單獨的程式中,而是和所在應用共用同一個程式。
  2. Service 也是在主執行緒中執行,所以一些耗時操作,依然需要單獨開啟執行緒去執行。

第一個問題其實並不是什麼大的問題,但是正常來說,我們使用 Service 就是想在後臺執行一些其他的操作,例如:下載等,而這些,又需要額外開啟執行緒來完成任務,這樣無形之中加大了我們的程式碼量。

而 IntentService 就是為這個而生的。

二、什麼是IntentService

IntentService 是繼承自 Service 的,所以它本質上還是一個 Service 。在 IntentService 內部維護了一個 WorkerThread 來專門處理耗時操作,實際上它會將所有 IntentService 的業務操作都放在 WorkerThread 中執行。

如果 start 了多次相同的 IntentService ,那麼每一次 start 的任務,都會在 WorkerThread 中依次執行。而最讓我們省心的是,IntentService 在執行完這些任務之後,會呼叫 stopSelf() 結束自己。

從官方文件可以瞭解到,一些 IntentService 的特點:

  1. 它會建立獨立的 WorkerThread 來處理所有的 Intent 請求。
  2. 它會建立獨立的 WorkerThread 來處理 onHandleIntent() 的實現程式碼,無需擔心多執行緒的問題。
  3. 所有請求完成之後,IntentService 會自動停止。
  4. 它的 onBind() 預設返回 null,不要去實現它,不要用 bindService() 繫結一個 IntentService。
  5. 它的 onStartCommand() 提供了預設的實現,會將請求的 Intent 新增到佇列中。

從上面的介紹可以瞭解到,在 IntentService 開啟了一個獨立的 WorkerThread 來完成具體任務的執行,而我們只需要將需要完成的業務程式碼,在 onHandleIntent() 中實現即可。

三、如何使用 IntentService

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

IntentService 本身已經幫我們實現了大部分邏輯,我們只需要在 onHandleIntent() 中實現我們的業務邏輯程式碼即可。

活兒好又不糾纏的 IntentService

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(),我們來看看輸出的結果。

活兒好又不糾纏的 IntentService

可以看到,每次 startService 的 startId 都不相同,而 IntentService 每次執行完成當前任務之後,會根據 startId 呼叫 stopSelf() 方法來標記需要停止服務,當最終沒有需要執行的任務的時候,才會 onDestory() 銷燬自己。這個細節,下一小結會詳細講解。

三、IntentService 如何實現它的特性

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

那麼我們就來從原始碼的角度,看看它是如何實現的。本身整個類,也只有不到二百行程式碼,真實有效的程式碼也就那麼十幾行,非常好理解。

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

活兒好又不糾纏的 IntentService

可以看到它實際上是使用了一個 HandlerThread 來維護執行緒的,而在 HandleThread 中,內部已經維護一個 Looper,這裡直接使用 HandlerThread 的 Looper 物件,便於在 IntentService 中去維護訊息佇列,而這裡最終建立的 mServiceHandler 是屬於 HandleThread 這個 WorkerThread 的。

活兒好又不糾纏的 IntentService

而在 ServiceHandler 中,直接轉發 Message 中攜帶的 Intent 物件,給 onHandleIntent() 方法去執行具體的業務邏輯。執行完成之後,立即呼叫 stopSelf() 方法停止自己,注意這裡 stopSelf() 方法的引數是 arg1。

接下來看看當我們呼叫 startService() 的時候,IntentService 到底幹了什麼?

活兒好又不糾纏的 IntentService

onStartCommand() 中直接呼叫了 onStart() 方法,而上面 stopSelf() 方法使用的 arg1 正是這個 Service 的 startId,也就是說,它是會指定 startId 來停止當前的此次任務服務。而 Service 如果被啟動多次,就會存在多個 startId ,當所有的 startId 都被停止之後,才會呼叫 onDestory() 自我銷燬。這也解釋了為什麼多次 start 同一個 IntentService 它會順序執行,全部執行完成之後,再自我銷燬。

活兒好又不糾纏的 IntentService

最終會在 onDestory() 中呼叫 quit 去退出 Looper 的迴圈,釋放資源。

四、查缺補漏

本身 IntentService 適用的場景,就是一種無狀態的 Service,所以它是不支援 bindService() 方法去 bound 一個服務的。正如它的 onBind() 實現,直接返回一個 null。

活兒好又不糾纏的 IntentService

當然如果你強制想要使用 bindService() 去實現 onBind() 方法,也是可以的,比較 IntentService 本身也是一個 Service,但是這樣就不符合 IntentService 的設計規範,破壞了它使用完成之後自我銷燬的理念,這個時候還是推薦使用正常的 Service 即可。

而如果確實有完成之後互動的需求,可以考慮使用 EventBus 或者 LocalBroadcastManager 這種通訊的方式來傳遞資料,都是一種不錯的方案。

活兒好又不糾纏的 IntentService
公眾號二維碼.jpg

相關文章