Android四大組件 — Service介紹

簡介

YanhHao Chang
7 min readJul 3, 2019

Android有四大組件Activity,Service服務,Broadcas tReceiver廣播接收器,Content Provider內容提供者。接下來將逐一介紹,今天先來初步探討Service。

Service是Android中實現背景運行的一種解決方案,他適合執行那些不需要和使用者互動且需長期執行的工作,就算是App被切換到背景也不影響Service的執行。

Service的使用首先需要定義一個繼承 Service 的類別,並override其中的生命週期函數,其中強制要求override的是onBind(),因為onBind()是一個abstact method,最後在Android Manifest內註冊我們自定義的Service類別才可以使用。

生命週期

Service的生命週期較Activity比起來相對簡單,因為Service在執行時並沒有UI畫面,所以少了Activity的一些畫面的生命週期,ex : onResume(),onPause(),onStop()…等等,下圖就是service的生命週期圖,其中startService() & bindService()分別是兩種啟動service的方法。

1. startService(intent)

透過 startService(intent) 啟動 Service,系統會先執行 onCreate(),然後將所傳進來的 intent 帶入 Service 的 onStartCommand(Intent, int, int)中,這個 Service 會一直執行,直到有人呼叫 stopService() 或內部呼叫 stopSelf() 才會停止。無論 startService() 被呼叫了多少次,只要執行一次 stopService(),或在 Service 內執行 stopSelf(),就會被停止(第一次啟動 Service 時才會執行 onCreate())。

生命週期 : onCreate() ➞ onStartCommand() ➞ onDestroy()

※利用 startService(intent) 啟動 Service,開啟後此 Service 便與調用者沒有任何的關係,也就是說,調用該服務的 activity 即便是退出了也不會影響 Service 的運行。而從 activity 亦不能去調用 Service 裡面的方法 。

2. bindService(intent, mServiceConnection, int flags)

透過 bindService(intent, mServiceConnection, int flags) 建立一個與 Service 綁定的連線,首先我們必須先建立一個 serviceConnection 物件,把這物件當作參數放到 bindService 內,flags 參數預設 BIND_AUTO_CREATE,也就是當我們綁定的時候會自動產生 Service。

生命週期 : onCreate() ➞ onBind() ➞ onUnbind() ➞ onDestroy()

※利用 bindService(intent, ServiceConnection, int flags) 啟動 Service,開啟後此 Service 便與調用者一起存活或是退出,也就是說,調用該服務的 activity 一退出, Service 的運行也會一起終止。而從 activity 可以透過 IBinder 物件取得 Service 物件,直接操作 Service 內各個 public 的 method。

這邊直接用例子做說明比較好懂,直接附上程式碼,先建立繼承Service的自訂類別MyService,並覆寫相關的方法,還另外建立了繼承Binder的類別MyBinder,在bindService時模擬背景請求工作。

進階了解

1. Service在onCreate時可以執行耗時工作嗎?

我們必須注意的是,Service的三個基本生命週期,onCreate()、onStartCommand()、onDestory()所在的執行緒都是主執行緒(MainThread),我們必須避免在主執行緒執行耗時的工作。 所以若是需要執行相關耗時工作我們必須借助Thread、Handler…等執行緒切換的方法。

2.執行耗時工作需要注意哪些事項?

因為Service開始運行就會一直處於存活的狀態,所以我們耗時工作完成之後必須手動呼叫stopSelf()或stopService()方法來停止當前啟動的Service,綜合以上1、2兩點可以發現其實Service的背景工作在操作上還多小細節需要注意,很多開發者常常忘記或是根本不知道必須這樣使用,所以Android官方很貼心的提供了 IntentService 類別,這個類別可以輕鬆地幫助開發者避免上述情形的發生。

3. IntentService 使用

IntentService的使用非常的簡單易懂,創建一個class繼承IntentService,override onHandlerIntent方法,從此方法可以知道我們在啟動IntentService時是使用Intent來發動,所以想單然爾也可以藉由Intent來攜帶一些data過來

結論

當我們知道了Service的用途,心中有一個Service相關的概念時,針對實際的場景還是要做具體的分析再決定是否使用Service。因為Service仍然是在主執行緒中調用,還是要開新的執行緒才能處理長時間的工作,Service和UI的交互也讓這個方式變得不那麼簡便。如果你只需要在當前界面去做一些耗時操作,界面退出或改變時,工作也要停止,那麼這時直接使用Thread(或者AsyncTask、ExecutorService…等)會更合適你。

附上github : https://github.com/XjojoX1989/ServiceLab

[補充]一些額外的Service知識

資料來源:https://github.com/francistao/LearningNotes/blob/master/Part1/Android/Android%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86.md

目前能否保證service不被殺死?

Service設置成START_STICKY

  • kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣。

提升service優先級

  • 在AndroidManifest.xml文件中對於intent-filter可以通過android:priority = "1000"這個屬性設置最高優先級,1000是最高值,如果數字越小則優先級越低,同時適用於廣播。
  • 【結論】目前看來,priority這個屬性貌似只適用於broadcast,對於Service來說可能無效。

提升service進程優先級

  • Android中的進程是託管的,當系統進程空間緊張的時候,會依照優先級自動進行進程的回收。
  • 當service運行在低內存的環境時,將會kill掉一些存在的進程。因此進程的優先級將會很重要,可以在startForeground()使用startForeground()將service放到前台狀態。這樣在低內存時被kill的機率會低一些。
  • 【結論】如果在極度極度低內存的壓力下,該service還是會被kill掉,並且不一定會restart()。

onDestroy方法裡重啟service

  • service +broadcast 方式,就是當service走onDestory()的時候,發送一個自定義的廣播,當收到廣播的時候,重新啟動service。
  • 也可以直接在onDestroy()裡startService。
  • 【結論】當使用類似口口管家等第三方應用或是在setting裡-應用-強制停止時,APP進程可能就直接被幹掉了,onDestroy方法都進不來,所以還是無法保證。

監聽系統廣播判斷Service狀態

  • 通過系統的一些廣播,比如:手機重啟、界面喚醒、應用狀態改變等等監聽並捕獲到,然後判斷我們的Service是否還存活,別忘記加權限。
  • 【結論】這也能算是一種措施,不過感覺監聽多了會導致Service很混亂,帶來諸多不便。

--

--