Services:可在後臺長時間運行,無UI界面。html
Started:android
Services經過其餘組件調用startService啓動,能在後臺一直運行,即便啓動它的組件已經銷燬。通常這種服務執行特定的操做並且沒有返回值,好比經過網絡下載或上傳一個文件,一旦操做結束,服務須要中止本身。安全
Bound:網絡
Service經過其餘組件調用bindService綁定,提供一個CS架構的接口容許其餘組件與Service交互、發消息、獲取返回值、甚至跨進程通訊。bound service與綁定它的組件共存亡,多個組件能夠綁定一個服務,當這個服務全部綁定它的組件都解綁後,服務會被銷燬。多線程
Caution:Service在宿主進程的主線程運行,也就是說Service不會建立本身的線程,也不會運行在另外一個進程(除非你指定)。這就意味着,若是Service執行一些高CPU負載或阻塞界面操做的任務時,你須要建立新的線程來運行它,以下降ANR的風險。架構
(使用service仍是thread?若是你只是須要在與用戶交互時,在主線程以外執行額外的任務,那麼你須要建立一個新線程而不是Service。好比在activity在前臺顯示的時候播放音樂,你須要在onCreate裏面建立線程,在onStart執行線程,在onStop裏中止線程,固然也可使用AsyncTask或者HandleThread來替代線程類。)app
建立Service的子類,覆寫Service生命週期中的關鍵回調函數,若是有必要,提供綁定Service的機制。最重要的回調函數以下:ide
onStartCommand函數
系統在其餘組件調用startService啓動Service時執行,以後,Service一直在後臺執行。若是你實現了這個方法,那麼你有責任在Service完成其工做時經過stopSelf或stopService來中止Service。(若是隻是提供綁定Service,能夠不用實現這個方法)oop
onBind
系統在其餘組件調用bindService綁定Service時執行,在這個方法的實現中,你須要返回一個IBider接口用於clients與service交互。若是你不須要綁定,能夠直接返回null
onCreate
Service第一次建立時執行,在onStartCommand和onBind以前,用於執行一次性須要初始化好的數據。
onDestroy
service銷燬時執行,用於清理資源,相似線程、註冊監聽器,receiver等。
系統會在低內存時強制中止service。若是service綁定在一個有用戶焦點的activity,那麼它不多會被銷燬;若是服務定義爲在前臺運行的,那麼它永遠不會被銷燬。
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
android:name是惟一必填的屬性,其餘能夠選填。一旦你的應用發佈出去了,那麼android:name永遠不要再變。
爲了安全性,請使用顯式Intent啓動或綁定服務,而不是定義filiters。若是確實容許多個服務來響應,那麼請務必在Intent中經過setPackage來指定報名,以下降目標服務匹配出意外值得機率。
設置android:exported爲false,能夠避免其餘應用啓動這個服務。
Service
全部服務的基類,若是你擴展這個類,那麼你可能須要建立一個新的線程,由於這個服務室在app的主線程中執行,有可能會下降activity的流暢度
IntentService
Service 的子類,經過工做線程來處理全部請求,每次處理一個。若是你的service不須要同時處理多個請求,IntentService是最佳的選擇。
由於大部分服務不須要同時處理多個請求(其實是個多線程場景),IntentService是最好的推薦
IntentService工做流程以下:
實際上,你須要作的就是實現onHandleIntent,以下例子:
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. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } }
若是你須要覆寫其餘回調,好比onCreate、onStartCommand、onDestroy,請確保要調用父類的實現,這樣IntentService才能處理工做線程的生命週期。onHandleIntent和onBind是例外。
若是服務須要支持多線程(而不是經過工做隊列來一一處理),那麼你要擴展Service來處理每個intent。
做爲對比,以下代碼和上面代碼功能同樣。
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. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // 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處理,有必要的話,你能夠爲每個請求建立一個線程。
onStartCommand必須返回一個整型,這個值用來描述系統如何處理這個服務,當它被異常銷燬時。
若是服務執行完onStartCommand後被異常銷燬,不須要從新建立服務,除非還有未處理的intents。避免服務被沒必要要地啓動,你的應用可以很容易地從新啓動未完成的工做,選擇這個。
若是服務執行完onStartCommand後被異常銷燬,從新建立服務並執行onStartCommand,可是不會使用發給這個服務的最後一個intent,而是經過一個null intent來執行onStartCommand,除非還有未處理的intents。這種狀況比較適合不執行命令,一直在後臺運行或者等待任務的媒體播放。
若是服務執行完onStartCommand後被異常銷燬,從新建立服務,用發給這個服務的最後一個intent調用onStartCommand,其餘未處理的intents依次分發。這種狀況適合執行的任務須要理解恢復的場景,好比下載文件。
startService –> onStartCommand
Intent intent = new Intent(this, HelloService.class); startService(intent);
startService方法當即返回。
若是service不能綁定,只能經過startService啓動,並且須要發送返回值時,能夠經過建立帶延遲廣播的PendingIntent(用getBroadcast)來啓動服務,服務能用裏面的廣播來分發結果。
若是服務同步地處理多個請求,那麼不能在處理完一個請求直接銷燬,有可能其餘的請求剛發過來或者還在處理中。爲了不這種狀況,你能夠經過stopSelf(int)來確保關閉的服務就是剛處理完請求的,而不是其餘正在處理的服務,整型參數惟一標識服務實例。
詳見下一章節
服務一旦運行,能夠經過Toast Notifications和Status Bar Notifications提醒用戶。
在前臺運行的服務必須提供一個狀態欄的notification,來呈現運行狀態,除非服務被中止或者移除,不然notification不會消失。
好比:播放音樂,在狀態欄有個notification來告訴用戶當前播放的歌曲,提供用戶進入音樂播放器的入口
服務須要在前臺運行,須要調用startForground,第一個參數是notification的惟一標示(不能爲0),第一參數就是notification,好比:
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);
中止在前臺運行,能夠調用stopForeground。
public class ExampleService extends Service { int mStartMode; // indicates how to behave if the service is killed IBinder mBinder; // interface for clients that bind boolean mAllowRebind; // indicates whether onRebind should be used @Override public void onCreate() { // The service is being created } @Override public int onStartCommand(Intent intent, int flags, int startId) { // The service is starting, due to a call to startService() return mStartMode; } @Override public IBinder onBind(Intent intent) { // A client is binding to the service with bindService() return mBinder; } @Override public boolean onUnbind(Intent intent) { // All clients have unbound with unbindService() return mAllowRebind; } @Override public void onRebind(Intent intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } @Override public void onDestroy() { // The service is no longer used and is being destroyed } }
Note:不須要執行父類的實現。
完整的生命週期:onCreate —> onDestroy
活動的生命週期:onStartCommand/onBind —> onDestroy/onUnbind