Service基礎使用
Service是一個應用組件,它表示一個應用期望去執行一個不與用戶交互的較長的操作或者通過一些功能爲其他應用去使用。
作爲android四大組件之一,Activity負責與用戶交互,而Service則負責不與用戶交互的那些工作,比如後臺下載,後臺播放音樂等需在後臺長期運行的服務。
無用戶界面、在後臺運行、生命週期長
生命週期
service有兩種生命週期,由於啓動方式不同生命週期也不同。
startService()
@Override
public void onCreate() {
super.onCreate();
// 創建服務
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
// 開始服務
}
@Override
public void onDestroy() {
super.onDestroy();
// 銷燬服務
}
bindService()
@Override
public void onCreate() {
super.onCreate();
// 創建服務
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
//綁定服務
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
// 解綁服務
}
@Override
public void onDestroy() {
super.onDestroy();
// 銷燬服務
}
綁定式服務(Bound啓動方式)
綁定服務
通過bindService()啓動的Service
// 綁定服務
ServiceConnection mConnection = ServiceConnection() { ... };
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
解除綁定
// 解除綁定
unbindService(mConnection);
關於綁定Service的流程
- 實現一個ServiceConnection ,必須重寫兩個方法
- onServiceConnection():系統調用這個來傳送在service的onBind()中返回的IBinder.
- OnServiceDisconnected():Android系統在同service的連接意外丟失時調用這個.比如當service崩潰了或被強殺了
- 定義一個Intent,我們android四大組件都使用Intent進行交互
- 傳一個int值的flag:
- 0,如果不想設置任何值,就設置成0
- Context.BIND_AUTO_CREATE,綁定服務時候,如果服務尚未創建,服務會自動創建,在API LEVEL 14以前的版本不支持這個標誌,使用Context.BIND_WAIVE_PRIORITY可以達到同樣效果
- Context.BIND_DEBUG_UNBIND,通常用於Debug,在unbindService時候,會將服務信息保存並打印出來,這個標記很容易造成內存泄漏。
- Context.BIND_NOT_FOREGROUND,不會將被綁定的服務提升到前臺優先級,但是這個服務也至少會和客戶端在內存中優先級是相同的。
- Context.BIND_ABOVE_CLIENT,設置服務的進程優先級高於客戶端的優先級,只有當需要服務晚於客戶端被銷燬這種情況才這樣設置。
- Context.BIND_ALLOW_OOM_MANAGEMENT,保持服務受默認的服務管理器管理,當內存不足時候,會銷燬服務
- Context.BIND_WAIVE_PRIORITY,不會影響服務的進程優先級,像通用的應用進程一樣將服務放在一個LRU表中
- Context.BIND_IMPORTANT,標識服務對客戶端是非常重要的,會將服務提升至前臺進程優先級,通常情況下,即時客戶端是前臺優先級,服務最多也只能被提升至可見進程優先級,
- BIND_ADJUST_WITH_ACTIVITY,如果客戶端是Activity,服務優先級的提高取決於Activity的進程優先級,使用這個標識後,會無視其他標識。
非綁定式服務(Started啓動方式)
啓動服務
// 啓動服務
Intent intent = new Intent(this, MyService.class);
startService(intent);
停止服務
stopService(intent)
關於非綁定服務
- 使用這個方法啓動的服務,再次調用startService()傳入Intent即可與服務通信,因爲這種方式啓動的服務在完整的生命週期內onCreate()只會執行一次,而onStartCommand()會執行多次,我們每次調用startService()。
- 服務不會停止,直到服務自己調了stopSelf()方法或者其他組件調用了stopService() 方法或者服務自身報錯崩潰等情況才能停止服務。
通信
與服務間的通信大體有一下三種
- 萬能通信機制:廣播與本地數據共享(ContentProvider/SharePreference等等)
- Started啓動模式下的startService()方法:傳入一個Intent即可與服務通信,每次調用startService時,在onStartCommond方法中去處理Intent即可。
- Bound啓動方式下
- Service中實現IBinder進行通訊
- 使用Messenger(簡化版AIDL)
- AIDL
如果你的Service只是應用在本進程中,那麼只要使用第一種方法就可以滿足通訊,如果是其他進程的Service那麼你就要採取進程間通訊了(第2、3種方式)
前臺運行服務
服務可以通過調用startForeground來轉變爲前臺優先級
public final void startForeground(int id, Notification notification)
這個方法最後還是要調NotificationManager.notify(int id, Notification notification)
所以前面的id 就相當於notify方法的id,notification就是我們的通知體
如果你想從前臺移除這個Service了,那就調用stopForeground
public final void stopForeground(boolean removeNotification)
參數是一個移除通知的標識,如果服務在前臺運行時候被停止,狀態欄的通知也會被移除。
startService 與 bindService 差異
大體先總結一下幾點:
- 啓動方式:這是最明顯的,一個調startService(),一個調bindService();
- startService啓動之後,正常來講是無法返回結果的,也就是說前端頁面上是沒有辦法干涉Service內部的動作的(你要說發廣播或者監聽之類的我也沒法反駁,但是頁面級別UI操作至少沒辦法)
- 而bindService由於裏面重寫了IBinder方法,我們可以和service交互,發送請求,得到結果甚至執行IPC通信,而且我們重載onServiceConnected還可以監聽Service的狀態。
然而這兩種方式也並不是完全分開的,在我看來只是不同地方不同用法而已
也就是說我們start了一個Service之後,如果你想與之綁定,對內部進行操作,還是可以bindService的,只不過如果你bind了之後stopService()或 stopSelf()實際上並不能停止這個service,除非所有的客戶都解除綁定。
Service 與 IntentService
我這裏有一篇Service&IntentService的博客講了關於兩個的不同
總結
Service 的用途還是很廣的,還是得多看博客,多看源碼,多寫多用才能融會貫通