1. 程式人生 > >Android開發中的Service的兩種啟動方式的坑

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方式來使用。

也可以兩種方式結合來使用。