一段時間不用,知識點就會忘,所以整理下一些基本的知識點,加深下印象,便于以后復習。這篇說一下Android中四大組件之一Service的使用。
1 Service簡介
Service是可以在后臺執(zhí)行長時間運行的應用程序組件,不提供用戶界面。另一個應用程序組件可以啟動一個服務,即使用戶切換到另一個應用程序,它也將在后臺繼續(xù)運行。另外,組件可以綁定到一個服務來與它進行交互,甚至執(zhí)行進程間通信(IPC)。例如,服務可以從后臺處理網(wǎng)絡事務,播放音樂,執(zhí)行文件I / O或與內(nèi)容提供商交互。
服務基本上可以采取兩種形式:
- Started
當應用程序組件(如Activity)通過調(diào)用startService()啟動服務時,服務將“啟動”。一旦啟動,服務可以在后臺無限期運行,即使啟動它的組件被銷毀。通常,啟動服務執(zhí)行單個操作,并且不會將結果返回給調(diào)用者。例如,它可能會通過網(wǎng)絡下載或上傳文件。操作完成后,服務應該停止。 - Bound
當應用程序組件通過調(diào)用bindService()綁定到一個服務時,服務是“綁定的”。綁定服務提供客戶端 - 服務器接口,允許組件與服務交互,發(fā)送請求,獲取結果,甚至可以通過進程間通信(IPC)進行交互。只要綁定了一個應用程序組件,綁定的服務就會運行。多個組件可以同時綁定到服務,但是當所有組件都解除綁定時,服務將被銷毀。
雖然通常單獨討論這兩種類型的服務,但您的服務可以以兩種方式工作 - 它可以啟動(無限期運行)并允許綁定。這只是一個實現(xiàn)幾個回調(diào)方法的問題:onStartCommand()允許組件啟動它并onBind()允許綁定。
無論您的應用程序是啟動,綁定還是兩者兼容,任何應用程序組件都可以使用該服務(即使是單獨的應用程序),也可以以任何組件可以使用活動的方式啟動它Intent。但是,您可以將該服務聲明為私有,在清單文件中,并阻止其他應用程序的訪問。
注意: 服務在主機進程的主線程中運行 - 服務不會創(chuàng)建自己的線程,并且不會在單獨的進程中運行(除非另有指定)。 這意味著,如果您的服務將進行任何CPU密集型工作或阻塞操作(如MP3播放或網(wǎng)絡連接),則應在服務中創(chuàng)建一個新的線程來完成此工作。 通過使用單獨的線程,您將降低應用程序不響應(ANR)錯誤的風險,并且應用程序的主線程可以保留專用于與您的活動的用戶交互。
2 創(chuàng)建Service
創(chuàng)建服務,必須創(chuàng)建一個Service(或其一個現(xiàn)有子類)的子類。在實現(xiàn)中,您需要覆蓋處理服務生命周期關鍵方面的一些回調(diào)方法,并提供一種機制,使組件綁定到服務(如果適用)。應該覆蓋的最重要的回調(diào)方法是:
- onStartCommand()
當另一個組件(如Activity)通過調(diào)用startService()請求啟動該服務時,系統(tǒng)將調(diào)用此方法。一旦執(zhí)行此方法,該服務將啟動并可以無限期地在后臺運行。如果您實現(xiàn)這方法,您的責任是通過調(diào)用stopSelf()或stopService()停止服務。(如果只想提供綁定,則不需要實現(xiàn)此方法。) - onBind()
當另一個組件通過調(diào)用bindService()與服務綁定時,系統(tǒng)會調(diào)用此方法。在實現(xiàn)此方法時,必須提供一個客戶端用于與服務通信的接口,方法是返回IBinder。您必須始終實現(xiàn)此方法,但如果不想允許綁定,則應返回null。 - onCreate()
系統(tǒng)調(diào)用該方法時,在首次創(chuàng)建服務,執(zhí)行一次性建立過程(它在onStartCommand()或 onBind()調(diào)用之前)。如果服務已經(jīng)運行,則不會調(diào)用此方法。 - onDestroy()
當服務不再使用并被銷毀時,系統(tǒng)調(diào)用此方法。應該實現(xiàn)這一點,以清理任何資源,如線程,注冊的聽眾,接收者等。這是服務接收的最后一個呼叫。
public class ExampleService extends Service {
private static String TAG = "ExampleService";
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG,"onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind");
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG,"onDestroy");
}
}
如果組件通過調(diào)用startService()(其導致調(diào)用onStartCommand())啟動服務,則服務將保持運行,直到它停止自身stopSelf()或通過調(diào)用停止它stopService()。
請注意,onStartCommand()方法必須返回一個整數(shù)。整數(shù)是一個值,描述系統(tǒng)在系統(tǒng)殺死服務時如何繼續(xù)服務。返回值onStartCommand()必須是以下常量之一:
- START_NOT_STICKY
如果系統(tǒng)在onStartCommand()返回后殺死了服務,并且沒有待處理的intent,則會將Service從啟動狀態(tài)中刪除,并且不會重新創(chuàng)建服務了,直到明確的調(diào)用(Context.startService(Intent))。 當服務不再是必需的,并且應用程序能夠簡單地重啟那些未完成的工作時,這是避免服務運行的最安全的選項。 - START_STICKY
如果系統(tǒng)在onStartCommand()返回后殺死了服務,則將重新創(chuàng)建服務并調(diào)用onStartCommand(),但不會再次傳入上一個intent, 而是用null intent來調(diào)用onStartCommand() 。除非有待處理的intent啟動服務,在這種情況下,這些intent會繼續(xù)傳遞。這適用于不執(zhí)行命令但無限期運行并等待工作的媒體播放器(或類似服務)。 - START_REDELIVER_INTENT
如果系統(tǒng)在onStartCommand()返回后殺死了服務,則將重新創(chuàng)建服務并調(diào)用onStartCommand()(傳遞上一個發(fā)送給服務的intent),任何待處理的intent也都會依次送入。這適用于那些需要立即恢復工作的活躍服務,比如下載文件。
如果一個組件調(diào)用 bindService()創(chuàng)建服務(和onStartCommand()被不叫),那么服務只只要組件綁定到它運行。一旦服務從所有客戶端解除綁定,系統(tǒng)就會銷毀它。
Android系統(tǒng)只會在內(nèi)存不足時強制停止服務,并且必須為具有用戶焦點的活動恢復系統(tǒng)資源。如果服務被綁定到具有用戶焦點的活動,則不太可能被殺死,并且如果該服務被聲明在前臺運行(稍后討論),則幾乎不會被殺死。否則,如果服務啟動并長時間運行,系統(tǒng)會隨著時間的推移降低后臺任務列表中的位置,并且服務將非常容易被殺死 。
3 在清單中聲明服務
像Activity(和其他組件)一樣,必須在清單文件中聲明應用程序的的所有服務。
要聲明您的服務,請?zhí)砑?lt;service>元素作為<application>元素的子 元素。例如:
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
可以在<service>元素中包含其他屬性,例如啟動服務所需的權限以及服務應運行的進程等進程。該android:name屬性是唯一必需的屬性,它指定服務的類名。
android:name---服務類名
android:label --- 服務的名字,如果此項不設置,那么默認顯示的服務名則為類名
android:icon----服務的圖標
android:permission-申明此服務的權限,這意味著只有提供了該權限的應用才能控制或連接此服務
android:process--表示該服務是否運行在另外一個進程,如果設置了此項,那么將會在包名后面加上這段字符串表示另一進程的名字
android:enabled--如果此項設置為 true,那么 Service 將會可以被系統(tǒng)啟動,false,表示此Service不可以被啟動(也就是不能使用)。不設置默認此項為true(網(wǎng)上好多person都說默認值位false,這是不對的。)
android:exported--表示該服務是否能夠被其他應用程序所控制或連接,不設置默認此項為 false
為了確保您的應用程序安全,始終在啟動或綁定您時使用明確的意圖,Service并且不為服務聲明意圖過濾器。如果關鍵是您允許開始使用哪些服務的模糊性,您可以為您的服務提供意圖過濾器,并從中排除組件名稱Intent,然后您必須為intent設置包setPackage(),這樣可以確定目標服務。
另外,您可以通過包含android:exported屬性和設置為"false"來確保您的服務僅適用于您的應用。即使使用明確的意圖,這有效地阻止其他應用程序啟動您的服務。
4 開始服務
諸如Activity之類的應用程序組件可以通過調(diào)用startService()并傳遞一個指定服務的Intent來啟動服務,并包括要服務使用的任何數(shù)據(jù)。該服務Intent在onStartCommand()方法中接收到該intent。
Intent intent = new Intent(this, ExampleService.class);
startService(intent);
該startService()方法立即返回,Android系統(tǒng)調(diào)用該服務的onStartCommand()方法。如果服務尚未運行,則系統(tǒng)首先呼叫onCreate(),然后調(diào)用onStartCommand()。
當服務啟動時,它具有獨立于啟動服務的組件的生命周期,并且服務可以無限期地在后臺運行,即使啟動它的組件被銷毀。started的服務必須管理自己的生命周期。也就是說,系統(tǒng)不會停止或銷毀服務,除非它必須恢復系統(tǒng)內(nèi)存,并且服務在onStartCommand()返回后繼續(xù)運行。因此,服務應該通過調(diào)用stopSelf()停止自己當完成工作時,或者另一個組件可以通過調(diào)用stopService()來停止它。
5 綁定服務
應用程序組件通過調(diào)用bindService()以創(chuàng)建長期連接來綁定的服務。
當您希望通過應用程序中的Activity和其他組件通過service進行交互,或通過進程間通信(IPC)將某些應用程序的功能暴露給其他應用程序時,應創(chuàng)建綁定服務。
要創(chuàng)建bound的服務,您必須實現(xiàn)onBind()回調(diào)方法來返回一個IBinder,IBinder用于定義與服務通信的接口。其他應用程序組件可以調(diào)用bindService()來檢索該接口并開始調(diào)用該服務的方法。 該服務僅用于為與其綁定的應用程序組件提供服務,因此當沒有組件綁定到服務時,系統(tǒng)會將其銷毀。
要創(chuàng)建綁定的服務,首先要做的是定義一個接口,指定客戶端如何與服務進行通信。服務和客戶端之間的這個接口必須是一個實現(xiàn),IBinder是您的服務必須從onBind()回調(diào)方法返回的。一旦客戶端收到IBinder,它可以開始通過該接口與服務進行交互。
多個客戶端可以一次綁定到該服務。當客戶端完成與服務的交互時,它會調(diào)用unbindService()解除綁定。一旦沒有客戶端綁定到服務,系統(tǒng)會銷毀該服務。
實現(xiàn)綁定服務有多種方法,并且實現(xiàn)比起始服務更復雜,下一篇講一下其多種方法。
6 service的生命周期
Service生命周期(從創(chuàng)建到銷毀時)可以遵循兩個不同的路徑:
- start Service
當另一個組件調(diào)用startService()時,創(chuàng)建該服務。然后該服務無限期地運行,并且必須通過調(diào)用來停止自身stopSelf()。另一個組件也可以通過調(diào)用來停止服務stopService()。當服務停止時,系統(tǒng)會銷毀它 - bind Service
當另一個組件(客戶端)調(diào)用bindService()時,創(chuàng)建該服務。然后,客戶端通過IBinder接口與服務進行通信??蛻舳丝梢酝ㄟ^調(diào)用來關閉連接 unbindService()。多個客戶端可以綁定到同一個服務,當它們?nèi)拷獬壎〞r,系統(tǒng)會銷毀該服務。(服務不需要自行停止。)
這兩條路徑并不完全分開。也就是說,您可以綁定到已經(jīng)通過startService()啟動的Service。例如,背景音樂Service可以通過調(diào)用startService()啟動與Intent標識要播放的音樂。后來,可能當用戶想要對播放器進行一些控制或獲取關于當前歌曲的信息時,Activity可以通過調(diào)用bindService()來綁定到服務。在這種情況下,stopService()或者stopSelf()實際上并不停止服務,直到所有客戶端解除綁定。