2021/04/29

Android Service

Android Service

 

Android Service

簡述

  • Service可以在背景不斷的工作,直到停止或是系統無法提供資源為止。
  • Service 需要透過某Activity 或者其他Context 物件來啟動。
  • Service不需要和 user 互動,所以沒有操作介面。
  • 生命週期與Activity是各自獨立的,Activity就算關閉,Service仍然可以繼續執行。
  • 類似 BroadcastReceiver,需要定義一個繼承 Service 的類別,並覆寫其中的生命週期函數,最後在AndroidManifest.xml中宣告才能使用
  • Service可以同時支援 StartedBind 兩種模式。在這種情況下,Service 需要等到兩種模式都被關閉才會觸發onDestroy()事件。
  • Service 只有第一次被啟動時,會執行onCreate(),若重複啟動則不會執行onCreate()
  • Service的運作優先權相當的高,一般來說除非系統資源耗盡,否則 Android 不會主動關閉一個已被啟動的Service。一旦系統有足夠的資源,被 Android 關閉的Service也會被重新啟動。
  • 兩者都需要在AndroidManifest.xml宣告

Service 生命週期

根據執行方式的不同,啟動Service分為兩種,注意只有黃色區塊不一樣: 圖左- Started 模式;圖右- Bind 模式,並根據不同模式複寫白色框框裡的函式。

Started 模式

啟動此模式的 Service,即便退出 Activity 也不會影響 Service 的運行,且Activity無法調用 Service 的方法。

  • 啟動 Service 的方式

    • Client side (Activity):Context.startService(intent)
  • 關閉 Service 的方式

    • Client side (Activity):Context.stopService()
    • Service inside:stopSelf()
  • onStartCommand() 最後需要回傳一個常數,這些常數定義在 Service 類別中。該回傳值是用在如果這個 Service 被 Android 作業系統終止後的行為:

    • Service.START_STICKY Service 如果被中止的話會自動重啟。用在onStartCommand()方法中不需要依賴Intent傳入的資料就可以執行的時候(重新啟動時重新傳入的Intent會是null)。這也是預設使用super.onStartCommnad()的回傳值。
    • Service.START_NOT_STICKY Servcie 如果被中止的話不重新啟動,用在onStartCommand()方法中所執行的工作需要依賴Intent物件內帶進來的參數。
    • Service.START_REDELIVER_INTENT START_STICKY 差不多,但 Android 會在中止 Service 之前將Intent保留下來,等待重新啟動時再將原本的Intent物件交還給onStartCommand()事件。

 

Bind 模式

啟動此模式的 Service,會伴隨著與調用者(Client)一起存活或是退出,當Activity退出Service的運行也會一起終止。

  • 啟動 Service 的方式

    • Client side (Activity):Context.bindService(intent, mServiceConnection, int flags)。其中第二個參數為ServiceConnection 物件,當bindService()綁定成功後,會呼叫此物件內的 onServiceConnected 函式,此函式會接收到由 Service 內的 onBind() 所丟出來的 IBinder 物件來直接操作 Service 內各個 public 的 method。 (ServiceConnection物件實作方式參考下方連結)
  • 關閉 Service 的方式

    • Service inside: unbindService(mServiceConnection);

 

解析 startService

透過以下範例了解startService運作流程,若需詳細程式碼請參考

測試角色

Service 端

  • TestService

Client 端

  • MainActive

結果

这里写图片描述

 

生命週期流程

这里写图片描述

 

再次分析onStartCommand() 的回傳值

  • START_NOT_STICKY

    • 表示當 Service 運行的 process 被 Android 系統強制殺掉之後,不會重新創建該 Service,當然如果在其被殺掉之後一段時間又調用了 startService,那麼該 Service 又將被實例化。
    • Ex:某個 Service 需要定時從 server 獲取最新數據:通過一個定時器每隔指定的N分鐘讓定時器啟動 Service 去獲取 server 的最新數據。當執行到 ServiceonStartCommand 時,在該方法內再規劃一個N分鐘後的定時器用於再次啟動 Service 並開闢一個新的執行緒去執行網絡操作。假設 Service 在從 server 獲取最新數據的過程中被 Android 系統強制殺掉,Service 不會再重新創建,這也沒關係,因為再過N分鐘定時器就會再次啟動該 Service 並重新獲取數據。
  • START_STICKY

    • 表示 Service 運行的 process 被 Android 系統強制殺掉之後,Android 系統會將該 Service 依然設置為 started 狀態(即運行狀態),但是不再保存 onStartCommand 方法傳入的 intent 對象,然後 Android 系統會嘗試再次重新創建該 Service,並執行 onStartCommand 回調方法,但是 onStartCommand 回調方法的 Intent 參數為 null,也就是 onStartCommand 方法雖然會執行但是獲取不到 intent 信息。
    • Ex:如果 Service 可以在任意時刻運行或結束都沒什麼問題,而且不需要 intent 信息,那麼就可以在 onStartCommand 方法中返回 START_STICKY,比如一個用來播放背景音樂功能的 Service 就適合返回該值
  • START_REDELIVER_INTENT

    • 表示 Service 運行的 process 被 Android 系統強制殺掉之後,與返回 START_STICKY 的情況類似,Android 系統會將再次重新創建該 Service,並執行 onStartCommand 回調方法,但是不同的是,Android 系統會再次將 Service 在被殺掉之前最後一次傳入 onStartCommand 方法中的 Intent 再次保留下來,並再次傳入到重新創建後的 ServiceonStartCommand 方法中,這樣我們就能讀取到 intent 參數。
    • Ex:如果 Service 需要依賴具體的 Intent 才能運行(需要從 Intent 中讀取相關數據信息等),並且在強制銷毀後有必要重新創建運行,那麼這樣的 Service 就適合。

解析 bindService

Client 與 Service 在同一個 App 中

透過以下幾個範例了解 bindService 的運作流程,若需詳細程式碼請參考

測試角色

Service 端

  • TestService

Client 端

  • 兩個 Activity,分別為 Active AActive B
  1. Activity A
  2. Activity B

測試流程

測試一

步驟
  • Activity A

    • click bindService
    • click unbindService
結果

測試二

步驟
  • Activity A

    • click bindService
    • click Finish
結果

測試三

步驟
  • Activity A

    • click bindService
    • click start Activity B
  • Activity B

    • click bindService
    • click unbindService
    • click Finish
  • Activity A

    • click unbindService
結果

生命週期流程

Client 與 Service 在同一個 App 中

參考

淺談 Service v.s. thread

  • 看似都是在背景運作,但實際上ServiceThread 沒有任何關係。

  • Service 是運行於主執行緒(Main Thread)上,故若在此執行太耗時的任務,依然會出現 ANR。

  • Thread 是用於開啟一個子執行緒(Child thread),去執行一些耗時作不會阻塞主執行緒的運行。

  • Activity 很難對 Thread 進行控制:

    • Activity 被銷毀後卻沒有主動停止 thread,就會造成没有辦法可以再重新獲取到之前建立的 thread 的實例。
    • 在某 Activity 中建立的 thread,另一個 Activity 無法對其進行操作。
  • Service 方便取得控制權:

    • Activity 被銷毀,其他的 Activity 都可以與 Service 重新進行關聯,就又能夠獲取到原有 Service 中 Binder 的實例。
    • 使用 Service 來處理後台任務,Activity 可以放心地 finish,完全不需要擔心無法對後台任務進行控制的情況。
  • 如果在Service內部做一些很耗時的任務,可以在Service內部建立一個執行緒來處理。因為Service是跑在主執行緒中,會影響到 UI 操作或是阻擋主執行緒的運行

    • ex:在後台播放多媒體檔案會需要檢查SD、在後台紀錄 gps 資訊的變換等等

Ref.

Service背景執行程式

《Android》『Service』- 背景執行服務的基本用法

Android中startService的使用及Service生命周期

Android中bindService的使用及Service生命周期

Android Service和Thread区别

 

沒有留言:

張貼留言