標籤:一般來說 stopself cte toast 調用 comment middle cli views
Service是一種能長期在後台運行同一時候不須要與使用者進行互動的應用組件。其它組件能夠開啟service,開啟後service能夠自行運行及時使用者已經切換到其它的應用。此外,組件能夠與service進行綁定來進行互動。及時是跨進程的互動(Android的IPC機制)。網路操作、播放音樂、運行檔案IO操作或是與內容提供者進行互動,這些操作都能夠通過service在後台進行。
Service的兩種形式:
Started
通過調用startService()。你能夠啟動一個service。一旦被啟動,service能夠獨立的運行在後台,即使啟動的組件被銷毀。
通常,被啟動的service用來運行一個單一的操作,而且沒有傳回值。比如,下載網路上的一個檔案。
當操作運行完畢後。service應當自行結束。
Bound
通過調用bindService(),你能夠綁定一個service。一個被綁定的service通常會提供一個介面用來與組件進行互動、發送請求、擷取結果、甚至進行進程間的互動(IPC)。
被綁定的service的生命週期和其綁定的組件同樣。雖然多個組件能夠同一時候綁定一個service,可是但全部這些組件進行解除綁定後。service會被銷毀。
雖然文檔中通常會對兩種形式的service分開介紹,可是你能夠同一時候開啟和綁定service。
僅僅須要同一時候覆寫兩個回調-onStartCommand和onBind就可以。
不管是用哪種方式啟動service(或是兩者都用),你都能夠使用Intent來操作service,就想操作Activity一樣。
然而。假設你不想讓其它應用使用你的service,你能夠在manifest檔案裡將service申明為私人的,詳細請看Service在資訊清單檔裡的申明。
基礎介紹
想要使用service,你須要繼承Service類或其子類。
你須要覆寫一些回調方法同一時候在這些方法中進行一些關鍵操作。一下是一些較為重要的生命週期回調回調:
onStartCommand()
系統會在你調用了startService後調用該函數。一旦該方法運行,service會被啟動並獨立運行在後台。假設你實現了該方法,你必須在合適的時機調用stopSelf()或者stopService()來停止service。(假設你僅提供綁定介面。你能夠不實現該方法)
onBind()
當有其它組件通過bindService()綁定service後,系統會調用onBind()函數。
你須要在該方法中提供一個實現了IBinder介面的類供給client使用。該方法必須要覆寫,假設你不希望你的service提供綁定功能,你能夠直接返回null。
Android系統會在記憶體較低時強制停止service;假設service被綁定在一個擁有焦點的activity上時。其被kill的風險會減少;假設一個service被申明為前台service。那麼它差點兒不會被kill。否者的話。假設service被長時間開啟。那麼隨著時間的推移,service在系統中的優先順序就會越低。被kill的風險就會越高。假設你的service被啟動了,那麼你就應該考慮到其被系統kill的情況。
假設系統kill了一個service。那麼在資源寬鬆的情況下。系統會重新啟動它(這個須要依據你在onStartCommand()的傳回值決定重新啟動的策略)。
Service在資訊清單檔裡的申明
和activity一樣,你須要在資訊清單檔裡申明service。
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application></manifest>
在service節點中能夠申明一些其它的屬性。這些屬性都是可選的。僅僅有android:name這一屬性是必須的——該屬性用來描寫敘述一個唯一的service類名,你應該確保不去改動該類名。
為了確保你的應用的安全性,應該使用顯式意圖來啟動或者綁定service,而且不在service中申明intent-filters。
此外,你能夠通過設定android:exported屬性為false來確保你的service僅能夠在你自己的應用中被使用。
這能夠有效得阻止其它應用使用你的service,即使通過顯式意圖也不能夠。
以啟動方式建立service
能夠通過startService()來啟動service。你能夠監聽到onStartCommand()回調。
當一個service被啟動後,它將擁有獨立的生命週期而且獨立的運行在後台。即使開啟它的組件被銷毀。這樣的情況下,你須要在合適的時機調用stopSelf()來結束它或者通過調用stopServie()來結束它。
調用startService()時傳遞的Intent會在onStartCommand()回調時接收到。
注意:service會預設運行在申明service的那個應用進程中。而且會運行在主線程中。
所以假設你的service在運行一些密集或堵塞的操作,那麼可能會造成ANR現象。為了避免這樣的情況。你須要開啟一個新的線程。
一般來說。你能夠通過繼承IntentService類來加速你的開發。
繼承IntentService類
由於大部分的service都不須要處理並發請求。因此你能夠通過繼承IntentService類來加速你的開發。
IntentService有下面特性:
1.建立了一個背景工作執行緒來運行由onStartCommand()中傳遞的intent。該線程是和主線程分離的。
2.建立了一個工作隊列用來依次運行intent,因此你不須要考慮多線程問題。
3.當全部任務運行結束後會自己主動的調用stopSelf()。
4.提供了onBind()的預設實現(return null)
5.提供了onStartCommand()的預設實現,發送任務到任務隊列中而且回調onHandleIntent()
上述這些特性使得你僅僅須要實現onHandleIntent()就能夠完畢client端的任務(你還須要提供一個簡單的建構函式)
下面是IntentService的一個實現:
public class HelloIntentService extends IntentService { /** * A constructor is required, and must call the super IntentService(String) * constructor with a name for the worker thread. */ public HelloIntentService() { super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); } }}
對照一下。假設你繼承自service要實現同樣功能所需寫的代碼:
public class HelloService extends Service { private Looper mServiceLooper; private ServiceHandler mServiceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); } // Stop the service using the startId, so that we don‘t stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process‘s // main thread, which we don‘t want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread‘s Looper and use it for our Handler mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we‘re stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don‘t provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); }}
是不是累覺不愛,果斷IntentService好啊。
然而,假設你希望實現並行作業,即不等上一個請求運行完畢就進行下一個請求的話。那麼直接繼承service是有必要的。
注意到onStartCommand()方法必須返回一個整型變數。這個整型變數用來指定當系統殺死service後應當怎樣返回。下面是各個傳回值:
START_NOT_STICKY
系統殺死service後不會又一次建立該service。除非須要傳遞pending intents。適用於當你的程式能夠簡單的重新啟動未完畢任務的service。
START_STICKY
假設系統殺死了service,那麼之後會重新啟動該service而且調用onStartCommand(),可是不會又一次發送上一個intent。而是返回一個null的intent(除非是一個pending intents。)這樣的模式非常適合音樂播放器這樣的不須要運行commands。可是須要獨立運行而且等待任務的service。
START_REDELIVER_INTENT
假設系統殺死了service,那麼之後會重新啟動該service而且掉哦那個onStartCommand(),而且會傳遞上一個intent。這中模式適合那些須要馬上返回的service,比例如以下載檔案。
以綁定方式啟動service
詳見Android開發文檔翻譯之-Bound Services
給使用者發送通知
一旦service運行,你能夠通過Toast Notifications或者Status Bar Notifications來告知使用者某些事件。
Toast Notifications是一種短時間內出如今當前表單表面的一條訊息。Status Bar Notifications是一種提供了表徵圖和訊息的通知欄,使用者能夠通過點擊來運行某個動作(比如開啟一個activity)
前台Service
前台Service通經常使用來運行一些須要使用者意識到正在啟動並執行一些操作,因此系統在低記憶體狀態時也不會kill掉該service。
前台Service須要在狀態列上提供一個通知,該通知不會消失,直到service被停止或者從前台移除。
比如,音樂播放器Service應該是被設定為運行在前台的service,由於使用者應該一直意識到這個操作。狀態列應該顯示當前現正播放的歌曲,而且當前點擊後應該跳轉到能和使用者進行互動的activity。
通過調用startForeground()函數能夠讓你的service運行在前台。使用示比例如以下:
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_ID, notification);
管理Service的生命週期
Service的生命週期相對Activity要簡單的多。可是卻更須要你注意。由於通常service是運行在背景。
Service的生命週期一般而言分為下面兩種:
Service的生命週期如所看到的。
原文連結:Android API文檔之Services
Android開發文檔翻譯之-Services