Android開發中的Service的兩種啟動方式的坑
和大家熟悉的Activity元件一樣,service也是Android應用開程式發中常用的元件,它和acitivy一樣也有自己的生命週期,不同的是service是執行在後臺的,沒有同用戶直接互動的介面。
service的是有兩種啟動方式:
第一種是通過startservice方式來啟動,通過此方式來啟動的service會一直執行在後臺,除非呼叫者主動停止服務或者是系統異常殺死。 此過程對應的生命週期是:
onCreate()----onStartCommand()-----onStop()----onDestory()
當呼叫者通過其他元件來呼叫一次startService之後,首先觸發onCreate(),然後是調觸發onStartCommand()
呼叫者停止服務後 觸發onStop和onDestory
這個過程中,無論startSrvice被呼叫多少次,onCreate只會執行一次,但是onStartCommand會執行多次,直到有人停止service觸發了onStop和onDestory。service才會重走生命週期
下面重點說一下onStartCommand()這個方法,這個函式有一個int的返回值,根據不同的返回值對應不同的情況:
START_STICKY
如果service程序被kill掉,保留service的狀態為開始狀態,但不保留遞送的intent物件。隨後系統會嘗試重新建立service,由於服務狀態為開始狀態,所以建立服務後一定會呼叫onStartCommand(Intent,int,int)方法。如果在此期間沒有任何啟動命令被傳遞到service,那麼引數Intent將為null。
START_NOT_STICKY
“非粘性的”。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統不會自動重啟該服務。
START_REDELIVER_INTENT
重傳Intent。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統會自動重啟該服務,並將Intent的值傳入。
START_STICKY_COMPATIBILITY
START_STICKY的相容版本,但不保證服務被kill後一定能重啟。
當呼叫者在外部通過stopService()或者在service內部通過StopSelf()方式停止了service,這個時候service是不回自動重啟。
所以為了程式的效能,我們在掉用了startService之後,一定要記得stopService,以免引起不可預知的錯誤。
第二種是通過bindService方式來啟動,通過此方式來啟動的service會和呼叫者的生命週期繫結,呼叫者被銷燬的時候,service也會被銷燬, 此過程對應的生命週期是:
onCreate()----onBind()-----onUnbind()----onStop()----onDestory()
當呼叫者通過其他元件來呼叫一次bindService之後,首先觸發onCreate(),然後是調觸發onBind()
呼叫者解除繫結後 觸發onUnbind--onStop和onDestory
這個過程中,無論bindService被呼叫多少次,onCreate只會執行一次,同樣onBind()也只會執行一次,直到有人解除繫結service觸發了onUnbind,直到onDestory。service才會重走生命週期,具體呼叫方式如下:
以在activity中繫結service為例
Intent mIntent = new Intent(context, GlassService.class);
bindService(mIntent, serviceConnection, Context.BIND_AUTO_CREATE);
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mGlassService = ((GlassService.MyBinder) iBinder).getGlassService();
if (mGlassService != null) {
......
......
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
.......
......
}
};
注意此處有坑,當我們使用同一個context和serviceconnection去執行bindservice時,onServiceConnected方法只會被回撥一次,除非我們傳入不同的context和serviceconnection去呼叫bindService才會去觸發onServiceConected回撥。因為onBind方法是返回的IBinder物件是通過onServiceConnected會來回調給呼叫者,當serviceConnection物件不變時,此回撥是不會多次呼叫的
,所以這個時候可以設定一個flag標誌位,來判斷是否需要多次bindService,在上面程式碼的基礎上改動如下:
if (isRegist) {
if (mGlassService != null) {
mGlassService.setIStausCallback(iStausCallback);
mGlassService.connectWifi();
}
} else {
Intent mIntent = new Intent(context, GlassService.class);
this.iStausCallback = iStausCallback;
context.bindService(mIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
isRegist = true;
mGlassService = ((GlassService.MyBinder) iBinder).getGlassService();
if (mGlassService != null) {
mGlassService.setIStausCallback(iStausCallback);
mGlassService.connectWifi();
mGlassService.setReleaseListener(GlassServiceState.this);
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
isRegist = false;
}
};
所以當我們通過bindService啟動service之後,一定要記得呼叫onUnbind方法來解除繫結,這樣才能保證onServiceConnected回撥能正常執行。
當然這兩種方式我們可以結合者使用:
當程式先通過bindservice呼叫之後,再通過startService呼叫。onCreate方法也只會執行一次。
這個時候如果呼叫unUnbind方法,service並不會被銷燬,也就說不會執行onDestory方法,直到使用者呼叫了StopService之後,Servie才會被銷燬。
當程式先通過StartService呼叫之後,再通過bindservice呼叫。onCreate方法也只會執行一次。
這個時候如果呼叫了StopService,service也不會被銷燬,直到使用者呼叫onUnbind方法,service才會被銷燬.。
總結:當我們只是單純的想啟動一個服務在後臺執行任務,無需和呼叫者進行資料互動,可以使用StartService方式
當想使用Service內部定義的功能的時候,也就是說需要和Service有互動的時候,可以使用bindService方式來使用。
也可以兩種方式結合來使用。