文章出處

概述

1、當用戶在與當前應用程序不同的應用程序時,Service可以繼續在后臺運行。

2、Service可以讓其他組件綁定,以便和它交互并進行進程間通信。

3、Service默認運行在創建它的應用程序的主線程中。

 

Service的使用主要是因為應用程序里面可能需要長時間地運行一些任務但是又不需要用戶界面或者應用程序本身需要對外提供一些函數給其他的應用程序調用。每一個Service實體類必須相應地在它的包中的AndroidManifest.xml有一個<service> 配置節的聲明。Services可以用 Context.startService()Context.bindService()來啟動。

下面我們將會涉及到幾個主題:

1、什么是Service?

2、Service的生命周期

3、進程生命周期

 

什么是Service?

很多Android的初學者都對Service抱有濃濃的疑惑,Service到底是什么,但是似乎更多的問題是Service到底不是什么

  • Service不是一個獨立的進程。Service不像他的名字所暗示的,它沒有自己獨立的進程;除非另外指定,Service運行在跟應用程序相同的進程中,并且他是應用程序進程的一部分。
  • Service不是一個線程。但也不是說Service就運行在界面主線程(Main Thread)中( Android中為了避免應用程序沒有響應的錯誤)。

其實Service非常簡單,它主要有兩個特性

  • 它是一種應用程序跟系統進行溝通的機制,告訴系統有一些任務要在后臺運行(即在用戶使用應用程序的時候)。我們可以對應地調用Context.startService()讓系統運行Service,Service會一直運行,直到Service本身或者其他人顯式地停止它。
  • 它是一個應用程序對外(其他應用程序)暴露函數接口的機制。我們可以對應地調用Context.bindService()來運行,這樣子其他的應用程序就可以長時間地跟Service連接,進行一些交互。

在一個Service組件被創建的時候,系統做的工作其實就是在主線程上實例化Service組件,然后調用Service的onCreate()還有其他Service的回調函數而已。也就是說,可以認為系統除了調用一下Service的函數,其他什么都不會再做了,如果你想要運行什么長時間的任務,比如從網絡上下載文件,那么跟以前一樣,你需要自己寫一個線程,當然是在Service內對應的函數中。

不過正因為Service本身如此簡單,我們可以自由定義Service,使之與外界進行一些簡單或者復雜的交互。我們可以將Service視為本地Java對象,進行直接的方法調用(具體的示例見Local Service Sample),也可以通過AIDL提供一個完全的遠程接口。

Service的生命周期

Service是由Android系統進行調度的。如果有人調用Context.startService(),系統就會將Service取回(有必要的時候創建它,并調用它的onCreate()方法)然后調用它的onStartCommand(Intent, int, int) 方法,使用客戶端提供的參數。這時候,Service會繼續運行運行直到Context.stopService() or stopSelf()被調用。注意:我們可以多次調用Context.startService()不會發送嵌套調用(盡管會有多次onStartCommand()的響應),所以不管Service多少次被啟動,它都只會在一次Context.stopService() 或stopSelf()的調用中被停止。然而,service可以使用它的stopSelf(int)方法來保證自己不會被停止,直到啟動它的intents被處理完。

 

對于一個啟動的服務(started Service)有兩種操作模型,這決定了它們不同的運行方式,而運行方式由它們的OnStartCommand()函數的返回值決定。START_STICKY適用于一個服務需要被明確地指定啟動或停止的情況。而while START_NOT_STICKYSTART_REDELIVER_INTENT使用于一個服務需要一直運行直到處理完它們收到的命令。

客戶端也可以使用Context.bindService() 去取得與一個Service的長連接。它同樣會創建一個Service,如果Service沒有運行(調用onCreate()來創建),但不會調用onStartCommand()。客戶端將會接收從service的onBind(Intent)方法返回的IBinder對象,從而客戶端就可以調用service上的方法了。只要客戶端和service的連接一建立,service就會一直保持運行狀態(無論客戶端是否有保存service的IBinder引用)。通常IBinder返回的是一個用aidl寫好了的復雜接口。

一個service可以同時被啟動和綁定。在這種情況下,系統會保持一個帶有 Context.BIND_AUTO_CREATE 標識的service一直運行只要他被啟動或者有一個或多個連接跟這個服務綁定著。一旦沒有被啟動和連接,service的onDestroy()就會被調用然后service就會被終止。在onDestroy()方法返回前,所有的線程和資源都應該被清理掉。

Process Lifecycle

前面我們講到,Service其實是運行在寄居在應用程序的進程當中的,也就是說當應用程序的進程被銷毀的時候,Service也就被銷毀了。當然,Android系統會盡力保證帶有Service的應用程序進程存活盡可能長的時候,只要進程中有Service已經啟動或者有別的客戶端需要使用著Service的服務。當Android系統內的內存不足,需要殺死一些進程來釋放內存時,在下面情況中,線程的優先級會因為Service而增高,進而減少被系統回收的可能性:

  • 如果進程中的Service正在執行onCreate(), onStartCommand(), 或 onDestroy()方法,那么這個進程就會變成前臺處理(foreground process)進程,進而能夠保證進程不會被回收。
  • 如果一個Service被啟動了,那么他的宿主進程就會被系統認為比當前用戶正在使用的的應用程序的進程更不重要,但比其他的后臺進程更重要。因為通常用戶當前只使用一小部分進程(也就是用戶看得見的進程),這意味著Service所在的進程不應該被回收掉,除非系統內存極度缺乏。
  • 如果一個客戶端(Client)跟Service綁定,那么這個Service的宿主進程會被系統認為跟客戶端進程是同等重要的,也就是,如果一個客戶端程序對用戶是可見的(也就是正在被使用),那么Service自身也會被認為是可見的。
  • 已經開始運行了的Service可以使用startForeground(int, Notification) API將當前進程放到前臺狀態(Foreground state),這樣系統就會認為他是用戶想要使用的進程,因此就不會成為低內存時的待回收進程。(但是理論上,在內存極度匱乏的情況下,這個進程仍有可能被回收。實際上,一般不會有這么極端的情況)。

注意,這說明當我們的Service正在運行的時候,它都不會被系統殺死,除非內存快滿了。如果Service被殺掉了,那么隨后系統還會嘗試著重新啟動Service。這樣子,我們就必須考慮到如果我們實現onStartCommand()方法,用異步或者其他線程來完成Service的任務,那么我們就可能需要使用START_FLAG_REDELIVERY 讓系統重新傳遞一個Intent,以便在Service重新啟動后,Intend會丟失。

在同一個進程中的應用程序組件(application components)像Service(或者Activity)可以增加進程在所有進程中的重要性,而不是僅僅增加Service的重要性。

 

補充說明:

前面談到Service是由系統進行調度的,那么對我們來講有什么意義呢?他又體現在什么地方呢?

因為Service是由系統進行調度的,那么它的生命周期與Activity的生命周期也就無關了,也就是假設ServiceA是由ActivityA啟動的,即使當ActivityA因為某種原因調用了OnDestroy()方法將自己銷毀掉之后,ServiceA依然歡快地運行著。


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()