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

也可以两种方式结合来使用。

猜你喜欢

转载自blog.csdn.net/EugeneYoung/article/details/81460367