从零开始--系统深入学习android(实践-让我们开始写代码-Android框架学习-2.service)...
第2章 Services
Service是一個長期運行在后臺,并不提供用戶界面的應用程序組件。其他應用程序的組件可以啟動一個service,并且即使用戶切換到另一個應用程序,service也可以在后臺繼續運行。此外,一個組件可以綁定到service與它進行交互,甚至執行進程間通信(IPC)。例如,一個service可能會處理來自后臺的所有事情,包括網絡事務、播放音樂、執行文件I/O或者與content provider交互。
一個service基本上有兩種形態:
1. 啟動態(Started):當應用程序組件調用startService()方法來啟動一個service時,service就處于“started”狀態。一旦啟動了service,即使啟動service的組件被銷毀,它也可以在后臺運行下去。通常,一個已啟動的service只執行單一的操作,且不會給它的調用者返回結果。例如,它可能通過網絡下載或上傳文件。當操作完成時,service應該要自行停止。
2. 綁定態(bound):當應用程序組件通過bindService()方法與service綁定時,service就處于“bound”狀態。一個綁定了的service會提供一個客戶端-服務器(CS)接口,組件可以通過這個接口與service交互、發送請求、獲取結果,甚至是跨進程的通信。只有當另一個應用程序與service綁定時,這個service才會運行。service可以與多個組件同時綁定,但是當它們全部解除時,service會被銷毀。
?? 盡管上面分別介紹了service的兩種類型,但你的service是可以在這兩種情況下同時工作的,它可以在被啟動的同時也能允許綁定。你只需要簡單地執行這兩種回調方法:允許應用程序組件啟動service的onStartCommand()方法和允許綁定的onBinding()方法。無論你的應用程序是啟動態、綁定態還是同時是這兩種狀態,任何應用程序組件都可以使用service(甚至從單獨的一個應用程序中),同樣的,任何組件也可以通過一個Intent來啟動activity進而使用這個activity。另外,你可以在manifest文件中,將service聲明為私有,并阻止來自其他應用程序的訪問。
注意:service是在宿主進程中的主線程上運行,因為service不會創建自己的線程,也不會在獨立的進程上運行(除非你另行指定)。這就意味著,如果你的service要執行任何密集使用CPU的工作或者阻塞操作(如MP3播放音樂或網絡工作),你就應該在service中創建一個新的線程來處理這些事情。通過使用一個獨立的線程,你將減少應用程序無響應(ANR)錯誤的風險,并且能讓應用程序主線程繼續處理用戶界面與activity的交互工作。
?
2.1 基礎知識
要創建一個service,你就必須創建一個service的子類(或者一個現有的子類)。在實現過程中,你需要重新寫入能處理service生命周期關鍵方面的回調方法,并且在適當條件下,提供一個將組件綁定到service的機制。下面是一些最重要的回調方法,你應該重寫它們:
1. onStartCommand():當另一個組件,如activity,調用startService()方法來請求啟動service時,系統會調用這個方法。一旦這個方法執行,service就處于已啟動狀態,并且會在后臺繼續運行下去。如果你實現這個方法,當工作完成后,你應該使用stopSelf()方法和stopService()方法來停止service(如果你只是想提供綁定,那你就不需要實現這個方法)。
2. onBind():當另一個組件想要通過調用bindService()方法與service綁定時,系統會調用這個方法。在這個方法的實現中,你必須提供一個接口讓客戶端與service通信,并返回一個Ibinder對象。你必須總是實現這個方法,但是如果你不想允許綁定,那么你應該返回null。
3. onCreate():當service第一次被創建,用來執行一次性設置的程序時(在調用onStartCommand()或onBind()方法之前),系統會調用這個方法。如果service已經運行了,那么這個方法不會被調用。
4. onDestroy():當service不再使用并且即將要被銷毀時,系統會調用這個方法。你的service應該實現這個方法來清除如線程、注冊監聽器、接收器等的所有資源。這是service接收到的最后一個調用。
討論:我們到底應該使用一個service還是一個線程?
??? 一個service是即使用戶不再與你的應用程序交互,它仍然可以在后臺運行的一個簡單組件。因此,你應該只要創建一個你真正需要的service。如果你需要執行在主線程以外的工作,但用戶正在與你的應用程序進行交互,那么你應該創建一個新線程,而不是一個新的service。例如,如果你想播放一些音樂,但你的activty正在運行,那么你可以用onCreate()來創建一個線程,onStart()方法開始運行它,然后用onStop()方法來停止它。你也可以考慮使用AsyncTask或HandleThread,而不是傳統的Thread類。要記住,如果你確實是要使用一個service,而它在默認情況下,仍然是在你的主線程上運行,那么如果你要執行密集型或阻塞操作,你應該還是要在你的service上創建一個新線程。
?
如果一個組件通過調用startService()(它會導致onStartCommand()方法的調用)方法來啟動service,那么service會一直運行,直到它使用stopSelf()方法自行停止了或者另一個組件通過stopService()方法停止了它。如果一個組件調用bindService()方法來創建service(onStartCommand()方法沒有調用),那么只有組件與service綁定,它才會運行。一旦services從所有的客戶端中解除,系統才會銷毀它。只有在內存很低和系統必須恢復系統資源時,Android系統才會強制停止service。如果service被綁定到一個獲取到用戶焦點的activity,那么service是不太容易被kill掉,并且如果聲明了service是在前臺運行,那么它幾乎是不會被kill掉。否則,如果service已經啟動并長時間在運行,那么系統會久而久之降低它在后臺任務列表中的位置,并且讓它變得很容易被kill掉-如果你的service被啟動了,那么你必須設計它怎樣優雅的通過系統來處理重新啟動的事件。如果系統kill掉了你的service,當他再次被重新啟動后,那么資源很快就變得可用了(盡管這取決于從onStartCommand()方法中返回的值)。下面將介紹如何創建各種類型的service,以及如何從其他的應用程序組件中使用它。
?
2.1.1? 在manifest中聲明service
?
?? 跟activity(和其他的組件)一樣,你必須在manifest文件中聲明所有的services。把一個<service>節點作為子節點添加到<application>節點中就可以聲明你的service,如代碼清單2-1所示:
<manifest ... >...<application ... ><service android:name=".ExampleService" />...</application> </manifest>?
代碼清單2-1
?? <service>節點還有幾個其他的屬性,包括定義屬性,如請求啟動service的權限和service應該運行的進程。指定service類名的啊android:name屬性是唯一必需的屬性。一旦發布了應用程序,你就不應該更改這個名稱,因為如果你改動了,你就可能破壞某些要用到隱式intents來引用service的功能。與activity一樣,service也可以定義intent filters,它允許其他組件通過隱式的intents來調用service。如果你聲明的intent filter與其他應用程序傳遞到startService()上的intent相匹配,那么安裝到用戶設備上的任何應用程序組件都可以啟動service。如果你計劃使用的是本地service(其他的應用程序不能使用它),那么你不需要(不應該)任何的intent filters。沒有intent filter的情況下,你就必須使用一個有明確類名的intent來啟動service。此外,只有把android:exported屬性包括進去并且把它設置成“false”,你才能確保你的service是對你的應用程序私有。即便你的service有intent filters,你的service仍然是為你的應用程序私有。
2.2 創建一個啟動態的service
?? 一個啟動態的service是另一個組件通過調用startService()方法啟動的,它會導致services的onStartCommand()方法的調用。當service啟動了,它就擁有了一個與啟動它的組件相獨立的生命周期,并且即使啟動它的組件被銷毀,service也會繼續在后臺運行。因此,當工作完成時,service可以調用stopSelf()方法來自行停止或者其他的組件通過stopService()方法來停止service。應用程序組件如activity,可以通過調用startService()方法來啟動一個service,并給它傳遞一個Intent。這個intent指定了你要啟動的service,并包含了service要用到的數據。service將會在onStartCommand()方法中接收到這個intent。例如,假設activity想把一些數據保存到一個在線數據庫中。那么Activity可以啟動一個service并通過一個intent來傳遞數據并使用startService()方法來保存的數據。這個service在onStartCommand()中接收到這個intent,與網絡連接并執行數據庫事務處理。當事務完成后,service會自行停止并會被摧毀。
注意:針對Android 1.6或更低版,如果你要創建一個適合Android 1.6或更低版的應用程序,你需要實現onStart()方法,而不是onStartCommand()方法(在Android 2.0中,onStart()被棄用,它支持onStartCommand()方法)。還有默認情況下,service運行在與activity相同的進程中,并且是在這個應用程序的主線程上運行。所以,當用戶與應用程序中的activity交互操作并且你的service要執行的密集或阻塞操作是在同一個應用程序時,service將會減弱activity的性能。為了避免影響到應用程序的性能,你應該在service中啟動一個新的線程。
?
傳統來說,你可以繼承下面兩個類來創建一個啟動態的service。
1. Service:這是所有service的基類。當你繼承這個類時,你可以在service中創建一個新的線程來處理service的所有工作,因為默認情況下,service會使用你的應用程序上的主線程,它會減弱應用程序中所有正在運行的activity的性能。
2. IntentService:這是service的子類,它使用一個工作線程來處理所有啟動的請求,每次只有一個線程存在。如果你不想service同時處理多個請求,那么這個類是最好的選擇。你所需要做的只是實現onHandleIntent()方法,它會為每個啟動service的請求來負責接收intent,這樣你就可以在后臺做這些工作。下面將介紹如何用這些類中的一個來實現你的service。
2.2.1? 繼承IntentService類
??? 因為大多數啟動的service不需要同時處理多個請求(實際上同時處理多個請求的情況是多線程),所以,實現service的最好辦法也許是使用IntentService類。
IntentService類會執行下面這些工作:
1.創建一個默認的工作線程,在onStartCommand()方法中執行所有傳遞過來的intents,這個線程獨立于應用程序的主線程。
2.創建一個工作隊列,在你實現的onHandleIntent()方法中,每次只會只會傳遞一個intent,這樣你就不必擔心多線程操作了。
3.所有的啟動請求都已經處理完了,就會停止service,這樣你永遠都不需要調用stopSelf()方法。
4.提供一個onBind()方法的默認實現,他返回null。
5.提供onStartCommand()方法的默認實現,這個方法會把intent發送給工作隊列,然后在onHandleIntent()方法中處理它們。
所有這些都說明了,你需要做的事只是實現onHandleIntent()方法來處理由客戶端提供的工作(盡管你還需要為service提供一個小的構造函數),下面讓我們看下代碼清單2-2所示的例子:
public class HelloIntentService extends IntentService {/** * 需求一個構造函數,因為需要調用父類的構造函數方法,傳入一個字符串 用來表示工作線程的名字*/public HelloIntentService() {super("HelloIntentService");}/*** IntentService從默認的工作線程中調用這個方法并且傳入了一個啟動service的intent供我們使用。* 當這個方法返回時IntentService停止了service。*/@Overrideprotected void onHandleIntent(Intent intent) {// 通常我們在這做一些工作,例如下載一個文件。本例中我們只讓它休眠5秒 long endTime = System.currentTimeMillis() + 5*1000;while (System.currentTimeMillis() < endTime) {synchronized (this) {try {wait(endTime - System.currentTimeMillis());} catch (Exception e) {}}}} }?
代碼清單2-2
上面就是你所需要做的:一個構造函數和onHandleIntent()方法的實現。如果你決定覆蓋其他的回調方法,如onCreate、onStartCommand()或者onDestroy(),那么就一定要確保調用父類方法的實現,這樣IntentService()方法才能處理好工作線程的生命周期。
例如,onStartCommand()方法必須返回默認父類的實現(這是intent傳遞到onHandleIntent()方法的途徑),如代碼清單2-3所示:
@Override public int onStartCommand(Intent intent, int flags, int startId) {Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();return super.onStartCommand(intent,flags,startId); }?
代碼清單2-3
?? 除了onHandleIntent()方法之外,僅有一個onBind()方法你不需要調用父類的實現(但是,如果你的service允許綁定,你就只需要實現它)。下面將介紹,當繼承service基類時是如何的實現相同的service,這個類的代碼稍微多一點,但是如果你想處理同時發起的多個請求的話,這個類也許是適合的。
2.2.2? 繼承service類
正如前面所說的,用IntentService類來實現啟動的service是非常簡單的。然而,如果你想你的service能執行多線程操作(而不是通過工作隊列來處理啟動請求),那么你可以繼承Service類來處理這些intents。經過比較,下面這個service類的實現代碼,與上面那個使用IntentService類的示例所做的工作相同。也就是說,對于每一個發起的請求,它都能用一個工作線程來執行工作,并且每次只處理一個請求,如代碼清單2-4所示:
public class HelloService extends Service {private Looper mServiceLooper;private ServiceHandler mServiceHandler;// 從線程中處理接收到的消息private final class ServiceHandler extends Handler {public ServiceHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {//和上面一樣休眠5秒long endTime = System.currentTimeMillis() + 5*1000;while (System.currentTimeMillis() < endTime) {synchronized (this) {try {wait(endTime - System.currentTimeMillis());} catch (Exception e) {}}}// 工作結束后使用startID停止service stopSelf(msg.arg1);}}@Overridepublic void onCreate() {// 啟動線程執行service.注意我們創建一個單獨的線程是因為正常情況下service在主線程執行操作,可能會導致阻塞。 HandlerThread thread = new HandlerThread("ServiceStartArguments",Process.THREAD_PRIORITY_BACKGROUND);thread.start();//獲得HandlerThread的 Looper并用在我們的Handler中 mServiceLooper = thread.getLooper();mServiceHandler = new ServiceHandler(mServiceLooper);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();// 為每一個啟動請求發送一個消息來執行一個工作并傳遞startID,因為我們需要知道當完成工作時應該停止請求Message msg = mServiceHandler.obtainMessage();msg.arg1 = startId;mServiceHandler.sendMessage(msg);return START_STICKY;}@Overridepublic IBinder onBind(Intent intent) {// 不需要綁定 返回null即可return null;}@Overridepublic void onDestroy() {Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); }?
代碼清單2-4
?? 正如你看到的,這個類比使用IntentService類多了很多工作。然而,因為你能自行處理onStartCommand()方法的每次調用,所以你可以同時執行多個請求。這個例子沒有這樣做,但是如果你想這樣做,那么你可以為每個請求創建一個新線程并立刻運行它(而不是等到上一個請求完成后才執行)。要注意的是,onStartCommand()方法必須返回一個整數。這個整數是一個值,它描述了當系統kill掉service時,系統應該如何繼續這個service(onStartCommand()的默認實現會為你處理好,但你也可以修改它)。從onStartCommand()中返回的值必須是下面常量中的一個:
1. START_NOT_STICKY:如果系統在onStartCommand()方法返回后kill掉service,那么不要重新創建service,除非有一個特定的intents要傳遞。這是一種最安全的選擇,它避免執行不必要的service,并且你的應用程序能簡單的重新開始未完成的工作。
2. START_STICKY:如果系統在onStartCommand()返回后,kill掉service,那么就要重新啟動service并調用onStartCommand()方法,但不用傳遞最后的intent。相反,系統調用onStartCommand()方法,傳遞一個值為null的intent,除非有一個用來啟動service的特定intents,在這種情況下,這些intents就會被傳遞。這很適用于多媒體播放器(或類似的service),它們不需要執行命令,但是它還是會繼續運行并且等待執行工作。
3. START_REDELIVER_INTENT:如果系統在onStartCommand()方法返回后,kill掉services,那么就要重新啟動service并且調用onStartCommand()方法,并將最后的一個intent傳遞給onStartCommand()方法。反過來,任何特定的intents都會被傳遞。這適用于service去執行那些要立即恢復的工作,如下載文件。
2.2.3? 啟動一個service
你可以通過給startService()傳遞一個Intent(指定要啟動的service)來啟動一個service,在activity和其他的應用程序組件中都能這樣啟動。Android系統調用service的onStartCommand()方法,并且把這個Intent傳遞給它(你應該永遠都不要直接調用onStartCommand()方法)。例如,activity可以傳遞一個顯式的intent給startService()方法來啟動service,如代碼清單2-5所示:
Intent intent = new Intent(this, HelloService.class); startService(intent);?
代碼清單2-5
?? startService()會立即返回,然后Android系統會調用service的onStartCommand()方法。如果service沒有正在運行,那么系統會首先調用onCreate()方法,然后才調用onStartCommand()方法。如果service也沒有提供綁定,那么使用startService()方法是應用程序組件與service通信的唯一模式。如果你希望service返回一個結果,那么啟動service的客戶端可以為廣播(用getBroadcast()方法)創建一個PendingIntent,并且在啟動service的Intent中,把這個intent傳遞給service。然后service就可以用這個廣播來傳遞一個結果。多個啟動service的請求,會相應的導致多個service的onStartCommand()方法的調用。
2.2.4停止一個service
?? 一個啟動的service必須管理好自己的生命周期。也就是說,除非系統必須恢復它的內存,否則系統是不會停止或銷毀service的,并且在onStartCommand()方法返回后service仍可以繼續運行。所以,service必須通過調用stopSelf()方法才能自行停止,或者另一個組件調用stopService()方法來停止service。一旦用stopSelf()或stopService()方法來請求停止service,那么系統會盡快的銷毀service。然而,如果你的service正在同時處理多個onServiceCommand()的請求,那么你就不應該在處理完一個啟動請求后就停止你的service,因為你有可能已經接收到了一個新的啟動請求(第一個請求結束時停止service,這將會終結第二個請求)。為了避免這個問題,你可以用stopSelf(int)方法來確保停止service的請求總是基于最后的啟動請求。這也就是說,當你調用stopSelf(int)方法時,你會傳遞一個啟動請求的ID(會傳遞到onStartCommand()方法中)來停止相應的請求。然后,如果service在調用stopSelf(int)方法之前接收到一個新的啟動請求,那么這個ID就不會匹配,service也就不會停止了。
注意:當service工作完成后,應用程序停止service是很重要的,因為要避免浪費系統的資源和消耗的電池。如果有必要的話,其他的組件也可以通過調用stopService()方法來停止service。如果你激活綁定了service,你也必須在onServiceCommand()方法的回調中不斷的停止service。
2.3 創建一個綁定的service
綁定service是指:允許應用程序通過調用bindService()方法來綁定到它的一個service,這是為了建立一個長期的連接(一般不允許組件通過startService()來啟動它)。當你想services與activity和其他組件交互時,或者想通過進程間通信(IPC)向其他的應用程序展示你的應用程序功能時,你就可以創建一個綁定的service。要創建一個綁定的service,你就選必須實現onBind()回調方法,使它返回一個IBinder,這個IBinder能定義與service進行通信的接口。然后其他應用程序組件就調用bindService()來檢索這個接口,并開始調用service中的方法。只有當服務于它綁定的應用程序組件時,service才會存在,所以當沒有組件綁定service時,系統就會銷毀它(你不需要停止一個綁定的service,但是當service是通過調用onStartCommand()方法來啟動時,你才必須停止它)。要創建一個綁定的service,首先要做的第一件事是定義一個客戶端如何與service通信的接口。service和客戶端之間的接口必須是一個IBinder的實現,并且必須是從onBind()回調方法中返回的。一旦客戶端接收到IBinder,它就能通過接口與service進行交互了。多個客戶端可以同時綁定到一個service。當某個客戶端完成了與service的交互工作時,它就會調用unbindService()方法來解除綁定。一旦沒有客戶端與service綁定了,系統就會銷毀service。
2.4 向用戶發送通知
?? 當運行service時,它可以用Toast Notifications或Status Bar Notifications向用戶發送事件通知。一個toast通知是出現在當前窗口上面的一個信息,它顯示一會就會消失,然而一個狀態欄通知是提供一個帶有信息的圖標,它顯示在狀態欄里,這樣用戶要執行動作的話就可以選擇它(如啟動一個activty)。通常來說,當一些后臺工作已經完成(例如,一個文件已經完成下載),一個狀態欄通知是最好的技術,因為用戶可以立刻執行那些后臺操作。當用戶從view中選擇通知時,這個通知就可以啟動一個activty(如查看下載好的文件)
2.5 在前臺運行service
一個前臺service是考慮做一些讓用戶特別關心的事情,并且它不是系統在低內存時要kill掉的候選。一個前臺service必須為狀態欄提供通知,并且放在持續性的標題欄的下方。這也就意味著通知是不會消失的,除非service它被停止了或把它從前臺移除。例如,一個從service播放音樂的播放器應該設置成在前臺運行,因為用戶很關心它的操作。在狀態欄中的通知可能會指示出當前播放的歌曲,并且允許用戶啟動一個activity來與音樂播放器進行交互。要使你的service能在前臺運行,就調用startForeground()方法。這個方法有兩個參數:一個int ID和一個用于狀態欄Notification,如代碼清單2-6所示:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),System.currentTimeMillis()); Intent notificationIntent = new Intent(this, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(this, getText(R.string.notification_title),getText(R.string.notification_message), pendingIntent); startForeground(ONGOING_NOTIFICATION, notification);?
代碼清單2-6
要把前臺的service移除的話,就調用stopForeground()方法。這個方法帶有一個boolean值,它表示是否能同時移除狀態欄通知。這個方法不能停止service。但是,如果你停止service,而它仍然在前臺運行,那么這個通知也會被移除。
注意:Android 2.0引用了startForeground()和stopForeground()方法(API級別5)。為了讓你的service能在舊版本的平臺運行,你必須使用先前的setForeground()方法。
2.6 管理Service的生命周期
Service的生命周期比activity的生命周期要簡單的多。但是,由于service可以在后臺運行,并且用戶察覺不到,所以更進一步的了解service是如何被創建和銷毀的就顯得更加重要。
從它被創建到被銷毀,service的生命周期可以遵從下面兩條路徑:
1.一個啟動態的service:當另一個組件調用startService()方法時,service就會被創建。然后service會無限期的運行,要調用stopSelf()方法才能停止它。另一個組件也可以調用stopService()來停止service。當service停止,系統就會銷毀它。
2.一個綁定態的service:當另一個組件(一個客戶端)調用bindService()方法,service就會被創建。這個客戶端通過一個IBinder接口就可以與service通信。它也可以調用unbindService()方法來關閉這種連接。多個客戶端可以與同一個service綁定,并且當所有的綁定都解除時,系統會銷毀service(service并不需要自行停止)。這兩條路徑并不是完全分開的。也就是說,你可以綁定一個已經用startService()方法啟動的service。例如,通過調用一個帶有Intent的startService()方法,可以啟動一個后臺播放音樂的service,這個Intent會指定要播放的音樂。之后,用戶可能想要對播放器進行控制或者獲取當前歌曲的信息,那么activity就可以通過調用bindService()方法來綁定到這個service。在這種情況下,stopService()或stopSelf()方法會直到所有的客戶端都解除,才能真正的停止service。
2.6.1實現生命周期回調方法
??? 和activity一樣,service有自己的生命周期回調方法,你可以實現這些方法來監測service的狀態變化,并且還可以在適當的時候處理一些工作。以下是一個service的框架,展示了它的每個基本生命周期方法,如代碼清單2-7所示:
public class ExampleService extends Service {int mStartMode; // service被killed掉后的啟動模式IBinder mBinder; // 用于客戶端的綁定接口boolean mAllowRebind; // 是否需要重新綁定 @Overridepublic void onCreate() {// service 被創建 }@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// service運行中,處理startService()方法的回調return mStartMode;}@Overridepublic IBinder onBind(Intent intent) {// 一個客戶端使用bindService()方法綁定service后的回調return mBinder;}@Overridepublic boolean onUnbind(Intent intent) {// 所有客戶端使用unbindService() 解除綁定時的回調return mAllowRebind;}@Overridepublic void onRebind(Intent intent) {// 一個客戶端在onUnbind()調用后,在調用bindService()的回調 }@Overridepublic void onDestroy() {// service不在被使用時 } }?
代碼清單2-7
注意:與activity生命周期回調方法不同的是,你不需要調用service方法的父類實現。
下面我們看下啟動態和綁定態兩種情況下的生命周期流程圖,圖2-1:
?
?
圖2-1 service的生命周期(左邊演示的是用startService()方法來創建一個service時的生命周期,右邊則是用bindService()方法創建一個service時的生命周期。)
?
通過實現這些方法,你可以監測service生命周期中的兩個嵌套循環:
1. 整體生命期:一個service的整循環是在調用onCreate()方法和onDestroy()方法之間出現的。和activity一樣,service在onCreate()方法中進行它的初始化設置,并用onDestroy()方法來釋放所有剩余資源。例如,一個音樂回放service可以用onCreate()方法創建一個播放音樂的線程,然后用onDestroy()方法來停止這個線程。無論這兩個方法是不是由startService()和bindService()方法創建,所有的services都會調用onCreate()和onDestroy()方法。
2. 激活生命期:一個service的激活生命期開始于onStartCommand()和onBind()方法的調用。每個方法都會分別處理傳給startService()方法或bindService()方法的Intent。如果service已經啟動,那么service的激活生命期會在整體生命期結束時也跟著結束(即使onStartCommand()方法返回了,service仍然是激活的)。如果service是綁定的,那么激活生命期會在onUnbind()方法返回時結束。
注意:盡管一個啟動態的service可以通過stopSelf()方法或stopService()方法來停止,但service沒有與此相應的回調方法(沒有onStop()回調方法)。所以,除非service與一個客戶端綁定,否則系統會在service停止時銷毀它,而onDestroy()方法是service能接收到的使它停止的唯一回調方法。
?
圖2-1展示了service的一個典型回調方法。盡管該圖把由startService()方法創建的service和由bindService()方法創建的service分開了,但要記住,不管service是如何啟動的,它都能允許客戶端綁定到它。所以,最初用onStartCommand()方法(客戶端調用startService()方法)啟動的service也仍然可以接收到onBind()方法的調用(當一個客戶端調用bindService()方法時)。具體更詳細的例子以后我們會在SDK下samples中講解
?
FAQ:QQ群213821767
總結
以上是生活随笔為你收集整理的从零开始--系统深入学习android(实践-让我们开始写代码-Android框架学习-2.service)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《面向模式的软件体系结构1--模式系统》
- 下一篇: Windows Server 2000