Service
可以在背景不斷的工作,直到停止或是系統無法提供資源為止。Service
需要透過某Activity
或者其他Context
物件來啟動。Service
不需要和 user 互動,所以沒有操作介面。Activity
是各自獨立的,Activity
就算關閉,Service
仍然可以繼續執行。BroadcastReceiver
,需要定義一個繼承 Service
的類別,並覆寫其中的生命週期函數,最後在AndroidManifest.xml
中宣告才能使用Service
可以同時支援 Started 與 Bind 兩種模式。在這種情況下,Service
需要等到兩種模式都被關閉才會觸發onDestroy()
事件。Service
只有第一次被啟動時,會執行onCreate()
,若重複啟動則不會執行onCreate()
。Service
的運作優先權相當的高,一般來說除非系統資源耗盡,否則 Android 不會主動關閉一個已被啟動的Service
。一旦系統有足夠的資源,被 Android 關閉的Service
也會被重新啟動。AndroidManifest.xml
宣告
<service
android:name=".MyService"
android:enabled="true" />
<!-- .MyService: 實作繼承Service的類別名稱 -->
根據執行方式的不同,啟動Service
分為兩種,注意只有黃色區塊不一樣:
圖左- Started 模式;圖右- Bind 模式,並根據不同模式複寫白色框框裡的函式。
啟動此模式的 Service
,即便退出 Activity
也不會影響 Service
的運行,且Activity
無法調用 Service
的方法。
Service
的方式
Activity
):Context.startService(intent)
Service
的方式
Activity
):Context.stopService()
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()
事件。
啟動此模式的 Service
,會伴隨著與調用者(Client)一起存活或是退出,當Activity
退出Service
的運行也會一起終止。
Service
的方式
Activity
):Context.bindService(intent, mServiceConnection, int flags)
。其中第二個參數為ServiceConnection
物件,當bindService()
綁定成功後,會呼叫此物件內的 onServiceConnected
函式,此函式會接收到由 Service
內的 onBind()
所丟出來的 IBinder
物件來直接操作 Service
內各個 public
的 method。ServiceConnection
物件實作方式參考下方連結)Service
的方式
Service
inside: unbindService(mServiceConnection);
透過以下範例了解startService
運作流程,若需詳細程式碼請參考
TestService
MainActive
...
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("DemoLog", "Thread ID: " + Thread.currentThread().getId());
Log.i("DemoLog", "before test startService");
//连续启动Service
Intent intent1 = new Intent(this, TestService.class);
startService(intent1);
Intent intent2 = new Intent(this, TestService.class);
startService(intent2);
Intent intent3 = new Intent(this, TestService.class);
startService(intent3);
//停止Service
Intent intent4 = new Intent(this, TestService.class);
stopService(intent4);
//再次启动Service
Intent intent5 = new Intent(this, TestService.class);
startService(intent5);
Log.i("DemoLog", "after test startService");
}
}
onStartCommand()
的回傳值START_NOT_STICKY
Service
運行的 process 被 Android 系統強制殺掉之後,不會重新創建該 Service
,當然如果在其被殺掉之後一段時間又調用了 startService
,那麼該 Service
又將被實例化。Service
需要定時從 server 獲取最新數據:通過一個定時器每隔指定的N分鐘讓定時器啟動 Service
去獲取 server 的最新數據。當執行到 Service
的onStartCommand
時,在該方法內再規劃一個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
信息。Service
可以在任意時刻運行或結束都沒什麼問題,而且不需要 intent
信息,那麼就可以在 onStartCommand
方法中返回 START_STICKY
,比如一個用來播放背景音樂功能的 Service
就適合返回該值START_REDELIVER_INTENT
Service
運行的 process 被 Android 系統強制殺掉之後,與返回 START_STICKY
的情況類似,Android 系統會將再次重新創建該 Service
,並執行 onStartCommand
回調方法,但是不同的是,Android 系統會再次將 Service
在被殺掉之前最後一次傳入 onStartCommand
方法中的 Intent
再次保留下來,並再次傳入到重新創建後的 Service
的 onStartCommand
方法中,這樣我們就能讀取到 intent
參數。Service
需要依賴具體的 Intent
才能運行(需要從 Intent
中讀取相關數據信息等),並且在強制銷毀後有必要重新創建運行,那麼這樣的 Service
就適合。透過以下幾個範例了解 bindService
的運作流程,若需詳細程式碼請參考
TestService
Activity
,分別為 Active A
與 Active B
Activity A
Activity B
Activity A
Activity A
Activity A
Activity B
Activity A
Service
與 Thread
沒有任何關係。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 操作或是阻擋主執行緒的運行
《Android》『Service』- 背景執行服務的基本用法
Android中startService的使用及Service生命周期
Android中bindService的使用及Service生命周期
Android service 启动篇之 startForegroundService
Service