Service
ref: 高效能執行緒
why use service?
將元件的生命週期跟Thread的生命週期分開(在Thread結束前無法釋放物件導致Memory leak)。
當一個Process內只剩下Thread在執行, 避免Process被系統意外回收, 導致Thread被提前結束。
Service生命週期
Service分成兩種類型
被啟動的Service:由第一個元件啟動請求建立, 第一個元件停止請求銷毀。其間,啟動請求僅傳遞給該service。
- 由start產生的service生命週期: onCreate → onStart\/onStartCommand → service is started → onDestroy → service is stopped
被聯繫的Service:第一個元件Bind, 該Service此時被建立, 直到所有元件Unbind才銷毀。
- 由bind產生的service生命週期: onCreate → onBind → service is bound → onUnbind → onDestroy → service is stopped
如果一個service在bind之後又進行start動作,在unbind之後,service還是會一直運作,直到stop動作被呼叫,service才會停止運行。反之,service先start,再bind的結果是一樣的。
- 生命週期: onCreate -> onStart\/onStartCommand -> service is started -> onBind -> service is bound & is started -> unBind -> service is still running -> onDestroy -> service is stopped 或者: onCreate -> onBind -> service is bound -> onStart\/onStartCommand -> service is started & is bound -> unBind -> service is still running -> onDestroy -> service is stopped
1. 啟動(Start)的Service
public class ServiceDemo extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override public IBinder onBind(Intent intent) {
return null;
}
}
啟動的service非常簡單, 只要覆寫onBind並且回傳null, 接著再多覆寫onStartCommand, 將Thread寫進此方法即可。
透過startService以及stopService控制啟動即結束, 也可以透過Service.stopSelf自行結束。
Service重啟
START_STICKY:Service被殺掉,系統會重啟,但是Intent會是null。
START_NOT_STICKY:Service被系統殺掉,不會重啟。
START_REDELIVER_INTENT:Service被系統殺掉,重啟且Intent會重傳。
2. 連繫(Bind)的Service
- 常用在IPC( Inter Process Communication ),亦指程序間的溝通技術。一般常見通用的有Socket、資料庫、檔案等。
- 透過Binder綁定機制進行遠端呼叫,並使用AIDL(Android Interface Definition Language)介面機制。
- bindService()和unbindService()控制 連結 或 取消 連結 service。
更多說明,可參考
ref:http://www.juwends.com\/tech\/android\/android-service-2.html
注意!
Service和UI沒有關連,所以Service的create、execute、stop service都需要佔用系統時間和memory空間。另外Android預設Service是在UI Thread中執行,所以這表示Service可能會影響到系統的流暢度。
使用Service應遵循以下規則:
避免誤用Service。
- 例如:不該用 Service 監聽某些事件的變化, 不應該使用Service在background對服務器不斷的進行輪詢(polling)→應該使用Google Cloud Messaging。
如果已經事先知道Service裡面的任務應該執行在Background Thread(非默認的主線程)的時候,我們應該優先使用IntentService或者結合HanderThread,AsycnTask Loader實現的Service。
Android系統為我們提供了以下的一些非同步( Asynchronous )執行相關的工具包:
- GCM
- BroadcastReciever
- LocalBroadcastReciever
- WakefulBroadcastReciver
- HandlerThreads
- AsyncTaskLoaders
- IntentService
如果使用上面的諸多方案還是無法替代普通的Service,那麼需要注意的就是如何正確的關閉Service。
IntentService vs. Service
Service
由Client端控制,User自行控制啟動跟結束。
並行任務執行:啟動多個Thread。
循序且可以重新安排的任務:任務可以被賦予優先權 e.g. 音樂服務。
IntentService
- 循序執行。
Foreground Service
這不能照字面翻譯(前景Service),不是工作在前景的Service。一般在Service運行在背景時,使用者無法得知此Service正運行背景。於是,開發者可透過 Foreground Service 所提供的機制 - Notification,通知使用者目前有正在運行的背景服務,這也是Android官方推薦的方法。而這種方法也可以讓系統在記憶體不足時,不會優先被系統給kill掉(通常被砍掉是看不到的背景服務)。
使用方法很簡單,在service啟動時,建立一個 Notification 並呼叫 startForeground() method即可;停止使用:呼叫 stopForeground() method 。
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);
public final void startForeground (int id, Notification notification) // id不能為0
public final void stopForeground (boolean removeNotification) //如要從前景移除服務,可以呼叫 stopForeground()。
//此方法有一個boolean,表示是否同時移除狀態列通知。
//此方法「不會」停止服務。
//然而,如果您在服務仍於前景執行時停止服務,則也會移除通知。
- 如果可以獲得系統權限的話, 也可以在AndroidManifest.xml的application增加
android:persistent="true"
如此一來也可以盡可能避免service被系統kill掉。