一、Service声明周期概述


二、生命周期方法具体介绍

手动调用方法 作用
startService() 启动服务
stopService() 关闭服务
bindService() 绑定服务
unbindService() 解绑服务
内部自动调用的方法 作用
onCreat() 创建服务
onStartCommand() 开始服务
onDestroy() 销毁服务
onBind() 绑定服务
onUnbind() 解绑服务

三、常见的声明周期使用

1、只使用startService启动服务的生命周期

当我们通过调用了Context的startService方法后,我们便启动了Service,通过startService方法启动的Service会一直无限期地运行下去,只有在外部调用Context的stopService或Service内部调用Service的stopSelf方法时,该Service才会停止运行并销毁。

要想使用Service,首先我们要继承自Service,然后重写如下方法: onCreate, onStartCommand, onBind 和 onDestroy。

这几个方法都是回调方法,都是由Android操作系统在合适的时机调用的,并且需要注意的是这几个回调方法都是在主线程中被调用的。

onCreate: 执行startService方法时,如果Service没有运行的时候会创建该Service并执行Service的onCreate回调方法;如果Service已经处于运行中,那么执行startService方法不会执行Service的onCreate方法。也就是说如果多次执行了Context的startService方法启动Service,Service方法的onCreate方法只会在第一次创建Service的时候调用一次,以后均不会再次调用。我们可以在onCreate方法中完成一些Service初始化相关的操作。

onStartCommand: 在执行了startService方法之后,有可能会调用Service的onCreate方法,在这之后一定会执行Service的onStartCommand回调方法。也就是说,如果多次执行了Context的startService方法,那么Service的onStartCommand方法也会相应的多次调用。onStartCommand方法很重要,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等。

onBind: Service中的onBind方法是抽象方法,所以Service类本身就是抽象类,也就是onBind方法是必须重写的,即使我们用不到。在通过startService使用Service时,我们在重写onBind方法时,只需要将其返回null即可。onBind方法主要是用于给bindService方法调用Service时才会使用到。

onDestroy: 通过startService方法启动的Service会无限期运行,只有当调用了Context的stopService或在Service内部调用stopSelf方法时,Service才会停止运行并销毁,在销毁的时候会执行Service回调函数。

用一张图来概括一下通过startService启动的Service的生命周期:


测试案例:

首先创建一个服务类TestService,该类继承自Service,代码如下:

import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class TestService extends Service {    @Override    public void onCreate() {        Log.i("DemoLog","TestService -> onCreate, Thread ID: " + Thread.currentThread().getId());        super.onCreate();    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.i("DemoLog", "TestService -> onStartCommand, startId: " + startId + ", Thread ID: " + Thread.currentThread().getId());        return START_STICKY;    }    @Override    public IBinder onBind(Intent intent) {        Log.i("DemoLog", "TestService -> onBind, Thread ID: " + Thread.currentThread().getId());        return null;    }    @Override    public void onDestroy() {        Log.i("DemoLog", "TestService -> onDestroy, Thread ID: " + Thread.currentThread().getId());        super.onDestroy();    }}
然后我们在Activity中调用该Serivce,Activity中相应的代码如下:
import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.util.Log;public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Log.i("DemoLog", "Thread ID: " + Thread.currentThread().getId());        Log.i("DemoLog", "before test startService");        //连续启动Service        Intent intent1 = new Intent(this, TestService.class);        startService(intent1);        Intent intent2 = new Intent(this, TestService.class);        startService(intent2);        Intent intent3 = new Intent(this, TestService.class);        startService(intent3);        //停止Service        Intent intent4 = new Intent(this, TestService.class);        stopService(intent4);        //再次启动Service        Intent intent5 = new Intent(this, TestService.class);        startService(intent5);        Log.i("DemoLog", "after test startService");    }}

我们在Activity中,首先连续三次调用了Activity的startService方法以启动Service,然后调用Activity的stopService方法停止Service,然后又通过调用Activity的startService方法启动Service。运行程序的输出结果如下:


我们分析一下上面的输出结果,首先打印出了主线程的ID是1, 然后我们发现后面所有在回调函数中打印出的执行线程的ID也就是1,这就说明了Service中的各个回调方法是运行在主线程中的。其次我们可以发现在我们连续调用了三次startService方法之后,只触发了一次onCreate回调方法,触发了三次onStartCommand方法,在onStartCommand中我们可以读取到通过startService方法传入的Intent对象,并且这三次的startId都不同,分别是1,2,3,每次调用startService都会自动分配一个startId,startId可以用来区分不同的startService的调用,一般情况下startId都是从1开始计数,以后每次调用startService之后startId自动加一递增。

之后我们又调用了Activity的stopService(intent4)方法用于停止Service,通过输出结果我们发现Service执行了onDestroy方法,一般情况下我们可以在onDestroy方法中执行一些资源释放的操作。执行完onDestroy之后该Service的实例就销毁了。虽然我们之前调用了三次startService方法,但是只要调用一次stopService就可以让运行中的Service停止运行并销毁。

最后我们再次通过startService(intent5)启动Service时,通过输出结果我们发现再次执行了Service的onCreate方法,这说明Service在通过stopService销毁之后重新创建了,并随之再次调用onStartCommand回调方法,并且startId再次从1开始计数。

最后需要注意的是我们在Activity中操作Service的开始和结尾处分别写了两句输出代码,分别是

Log.i("DemoLog", "before test startService");
  • 1

Log.i("DemoLog", "after test startService");
  • 1

但是我们再看一下输出结果会发现,程序直接上来在输出了before test startService之后,却立即输出了after test startService,在这之后才是TestService内部各个回调方法的输出,这说明startService()方法和stopService()方法在执行完后立即返回了,也就是这两个方法都不是阻塞式的,启动service和停止service都是异步操作,startService()、stopService()都是将intent对象发送给Android Framework,然后Framework层异步地启动、停止Service。

onStartCommand返回值说明:

当Android面临内存匮乏的时候,可能会销毁掉你当前运行的Service,然后待内存充足的时候可以重新创建Service,Service被Android系统强制销毁并再次重建的行为依赖于Service中onStartCommand方法的返回值。我们常用的返回值有三种值,START_NOT_STICKY、START_STICKY和START_REDELIVER_INTENT,这三个值都是Service中的静态常量。

START_NOT_STICKY: 如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service,当然如果在其被杀掉之后一段时间又调用了startService,那么该Service又将被实例化。那什么情境下返回该值比较恰当呢?如果我们某个Service执行的工作被中断几次无关紧要或者对Android内存紧张的情况下需要被杀掉且不会立即重新创建这种行为也可接受,那么我们便可将 onStartCommand的返回值设置为START_NOT_STICKY。举个例子,某个Service需要定时从服务器获取最新数据:通过一个定时器每隔指定的N分钟让定时器启动Service去获取服务端的最新数据。当执行到Service的onStartCommand时,在该方法内再规划一个N分钟后的定时器用于再次启动该Service并开辟一个新的线程去执行网络操作。假设Service在从服务器获取最新数据的过程中被Android系统强制杀掉,Service不会再重新创建,这也没关系,因为再过N分钟定时器就会再次启动该Service并重新获取数据。

START_STICKY: 如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,但是onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。如果你的Service可以在任意时刻运行或结束都没什么问题,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY,比如一个用来播放背景音乐功能的Service就适合返回该值。

START_REDELIVER_INTENT: 如果返回START_REDELIVER_INTENT,表示Service运行的进程被Android系统强制杀掉之后,与返回START_STICKY的情况类似,Android系统会将再次重新创建该Service,并执行onStartCommand回调方法,但是不同的是,Android系统会再次将Service在被杀掉之前最后一次传入onStartCommand方法中的Intent再次保留下来并再次传入到重新创建后的Service的onStartCommand方法中,这样我们就能读取到intent参数。只要返回START_REDELIVER_INTENT,那么onStartCommand重的intent一定不是null。如果我们的Service需要依赖具体的Intent才能运行(需要从Intent中读取相关数据信息等),并且在强制销毁后有必要重新创建运行,那么这样的Service就适合返回START_REDELIVER_INTENT。

2、只使用bindService绑定服务的生命周期

相比于用startService启动的Service,bindService启动的服务具有如下特点: 
1. bindService启动的服务在调用者和服务之间是典型的client-server的接口,即调用者是客户端,service是服务端,service就一个,但是连接绑定到service上面的客户端client可以是一个或多个。这里特别要说明的是,这里所提到的client指的是组件,比如某个Activity。 
2. 客户端client(即调用bindService的一方,比如某个Activity)可以通过IBinder接口获取Service的实例,从而可以实现在client端直接调用Service中的方法以实现灵活的交互,并且可借助IBinder实现跨进程的client-server的交互,这在纯startService启动的Service中是无法实现的。 
3. 不同于startService启动的服务默认无限期执行(可以通过Context的stopService或Service的stopSelf方法停止运行),bindService启动的服务的生命周期与其绑定的client息息相关。当client销毁的时候,client会自动与Service解除绑定,当然client也可以通过明确调用Context的unbindService方法与Service解除绑定。当没有任何client与Service绑定的时候,Service会自行销毁(通过startService启动的除外)。 
4. startService和bindService二者执行的回调方法不同:startService启动的服务会涉及Service的的onStartCommand回调方法,而通过bindService启动的服务会涉及Service的onBind、onUnbind等回调方法。

bindService代码示例

使用bindService主要分两种情形: 
1. Service的调用者client与Service在同一个App中; 
2. Service的调用者client是App1中的一个Activity,而Service是App2中的Service,client与service分属两个App,这种情形下主要用于实现跨进程的通信。

为了简单起见,本文只讨论第一种情形,即Service的调用者client与Service在同一个App中,该情形也是我们在实际开发中用到最多的情形。如果想了解通过bindService在两个不同的进程中让客户端与Service通信,可参见博文《Android中通过Messenger与Service实现进程间双向通信》。

下面我们通过一个例子演示一下第一种情形下bindService的基本使用流程。

首先我们有一个TestService,该类继承自Service,其是client-server接口中的server端。我们在其主要的生命周期回调方法中都加入了输出语句。TestService代码如下:

import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;import java.util.Random;public class TestService extends Service {    public class MyBinder extends Binder{        public TestService getService(){            return TestService.this;        }    }    //通过binder实现调用者client与Service之间的通信    private MyBinder binder = new MyBinder();    private final Random generator = new Random();    @Override    public void onCreate() {        Log.i("DemoLog","TestService -> onCreate, Thread: " + Thread.currentThread().getName());        super.onCreate();    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.i("DemoLog", "TestService -> onStartCommand, startId: " + startId + ", Thread: " + Thread.currentThread().getName());        return START_NOT_STICKY;    }    @Override    public IBinder onBind(Intent intent) {        Log.i("DemoLog", "TestService -> onBind, Thread: " + Thread.currentThread().getName());        return binder;    }    @Override    public boolean onUnbind(Intent intent) {        Log.i("DemoLog", "TestService -> onUnbind, from:" + intent.getStringExtra("from"));        return false;    }    @Override    public void onDestroy() {        Log.i("DemoLog", "TestService -> onDestroy, Thread: " + Thread.currentThread().getName());        super.onDestroy();    }    //getRandomNumber是Service暴露出去供client调用的公共方法    public int getRandomNumber(){        return generator.nextInt();    }}

在该App中,除了TestService,还有两个Activity: ActivityA和ActivityB,它们都是Service的调用者,即client-server接口中的client。

ActivityA是App的启动界面,界面如下: 


ActivityA的代码如下:

import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Button;public class ActivityA extends Activity implements Button.OnClickListener {    private TestService service = null;    private boolean isBound = false;    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder binder) {            isBound = true;            TestService.MyBinder myBinder = (TestService.MyBinder)binder;            service = myBinder.getService();            Log.i("DemoLog", "ActivityA onServiceConnected");            int num = service.getRandomNumber();            Log.i("DemoLog", "ActivityA 中调用 TestService的getRandomNumber方法, 结果: " + num);        }        @Override        public void onServiceDisconnected(ComponentName name) {            isBound = false;            Log.i("DemoLog", "ActivityA onServiceDisconnected");        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_a);        Log.i("DemoLog", "ActivityA -> onCreate, Thread: " + Thread.currentThread().getName());    }    @Override    public void onClick(View v) {        if(v.getId() == R.id.btnBindService){            //单击了“bindService”按钮            Intent intent = new Intent(this, TestService.class);            intent.putExtra("from", "ActivityA");            Log.i("DemoLog", "----------------------------------------------------------------------");            Log.i("DemoLog", "ActivityA 执行 bindService");            bindService(intent, conn, BIND_AUTO_CREATE);        }else if(v.getId() == R.id.btnUnbindService){            //单击了“unbindService”按钮            if(isBound){                Log.i("DemoLog", "----------------------------------------------------------------------");                Log.i("DemoLog", "ActivityA 执行 unbindService");                unbindService(conn);            }        }else if(v.getId() == R.id.btnStartActivityB){            //单击了“start ActivityB”按钮            Intent intent = new Intent(this, ActivityB.class);            Log.i("DemoLog", "----------------------------------------------------------------------");            Log.i("DemoLog", "ActivityA 启动 ActivityB");            startActivity(intent);        }else if(v.getId() == R.id.btnFinish){            //单击了“Finish”按钮            Log.i("DemoLog", "----------------------------------------------------------------------");            Log.i("DemoLog", "ActivityA 执行 finish");            this.finish();        }    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.i("DemoLog", "ActivityA -> onDestroy");    }}
通过单击ActivityA上的“start ActivityB”可以启动ActivityB,ActivityB的界面如下: 


ActivityB的代码如下:

import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Button;public class ActivityB extends Activity implements Button.OnClickListener {    private TestService service = null;    private boolean isBound = false;    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder binder) {            isBound = true;            TestService.MyBinder myBinder = (TestService.MyBinder)binder;            service = myBinder.getService();            Log.i("DemoLog", "ActivityB onServiceConnected");            int num = service.getRandomNumber();            Log.i("DemoLog", "ActivityB 中调用 TestService的getRandomNumber方法, 结果: " + num);        }        @Override        public void onServiceDisconnected(ComponentName name) {            isBound = false;            Log.i("DemoLog", "ActivityB onServiceDisconnected");        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_b);    }    @Override    public void onClick(View v) {        if(v.getId() == R.id.btnBindService){            Intent intent = new Intent(this, TestService.class);            intent.putExtra("from", "ActivityB");            Log.i("DemoLog", "----------------------------------------------------------------------");            Log.i("DemoLog", "ActivityB 执行 bindService");            bindService(intent, conn, BIND_AUTO_CREATE);        }else if(v.getId() == R.id.btnUnbindService){            if(isBound){                Log.i("DemoLog", "----------------------------------------------------------------------");                Log.i("DemoLog", "ActivityB 执行 unbindService");                unbindService(conn);            }        }else if(v.getId() == R.id.btnFinish){            //单击了“Finish”按钮            Log.i("DemoLog", "----------------------------------------------------------------------");            Log.i("DemoLog", "ActivityB 执行 finish");            this.finish();        }    }    @Override    public void onDestroy(){        super.onDestroy();        Log.i("DemoLog", "ActivityB -> onDestroy");    }}

我们暂时不点击上面的按钮,先看一下TestService和ActivityA的代码。

调用者(客户端client)要想和Service进行交互,那么Service和调用者必须都要做好准备。

我们先看Service要做的工作。 
使用bindService将client与server联系在一起的关键是binder,在TestService中,我们在其中写了一个内部类MyBinder,该类有个公共方法getService,通过该方法我们可以获取包含MyBinder的TestService。如果想要自己的Service支持bindService启动方式,就必须在Service的onBind中返回一个IBinder类型的实例。在示例中,我们实例化了一个MyBinder的实例binder作为TestService的字段,并且将其作为onBind的返回值。 
我们总结一下如果想让Service支持bindService调用方式,Service需要做以下事情: 
1. 在Service的onBind方法中返回IBinder类型的实例。 
2. onBind方法返回的IBinder的实例需要能够返回Service实例本身或者通过binder暴露出Service公共方法。通常情况下,最简单明了的做法就是将binder弄成Service的内部类,然后在binder中加入类似于getService之类的方法返回包含binder的Service,这样client可以通过该方法得到Service实例。

我们已经知道了Service需要做的事情,我们接下来看一下调用者需要做的工作。 
在我们的示例中,调用者(也就是客户端client)是ActivityA,我们在其中初始化了一个ServiceConnection类型的实例,需要重写其onServiceConnected方法以及onServiceDisconnected方法。我们需要将这个ServiceConnection类型的实例作为参数传给bindService方法,当Service还没有创建的时候,Android会先创建Service的实例,然后执行Service的onBind方法,得到IBinder类型的实例,将该方法作为参数传入client端的ServiceConnection的onServiceConnected方法中,onServiceConnected方法的执行表明client端可以获取到Service的IBinder类型的实例,然后将IBinder转换为自己实际的Binder类型,然后可以通过其直接获取Service的实例或者通过Binder直接执行公共方法,这取决于Service中Binder的具体实现。在本例中,在onServiceConnected方法中,调用者ActivityA通过binder的getService方法获取到了与其对应的Service,然后我们就可以直接调用Service的公共方法以达到使用Service的目的,这样client与Service之间就通过IBinder建立了连接,从而进行交互。当client与Service失去连接时会触发onServiceDisconnected方法。 
我们总结一下client端要做的事情: 
1. 创建ServiceConnection类型的实例,并重写其onServiceConnected方法和onServiceDisconnected方法。 
2. 当Android执行onServiceConnected回调方法时,我们可以通过IBinder实例得到Service的实例对象或直接调用binder的公共方法,这样就实现了client与Service的连接。 
3. 当Android执行onServiceDisconnected回调方法时,表示client与Service之间断开了连接,我们在此处要写一些断开连接后需要做的处理。

在知道了如何让client与Service进行交互之后,我们运行我们的App,观察各个回调方法的执行过程,我们有三个测试流程。

测试流程A

该测试涉及到ActivityA,但不涉及ActivityB. 
首先我们点击ActivityA中的“bindService”按钮,然后点击”unbindService”按钮,输出结果如下所示: 

首先,通过上面的代码我们可以看到Service中执行的回调方法都是执行在主线程中的。 
当我们调用bindService方法时,我们需要将Intent、ServiceConnection等实例传入,Intent包含了我们要绑定的Service,ServiceConnection我们在上面提到过,实现了其onServiceConnected方法和onServiceDisconnected方法。 在调用了bindService之后,由于Service此时还不存在,那么Android就会首先创建一个TestService的实例,并执行其onCreate回调方法,onCreate方法在其生命周期中只会被调用一次。然后会调用Service的onBind方法,该方法只有在第一次bindService调用后才会执行,onBind执行后会返回一个IBinder类型的实例,此时Android会将该IBinder实例存起来,这个IBinder实例是对所有client共享的。当下次其他的client执行bindService的时候,不会再执行onBind方法,因为我们之前已经得到了一个IBinder实例,Android会直接使用这个IBinder实例。 在得到了IBinder实例之后,Android会执行client端ServiceConnection中的onServiceConnected方法,在该方法中我们会得到IBinder实例,并通过该IBinder实例得到了TestService实例,这样我们的客户端ActivityA就通过IBinder与TestService建立了连接,我们就可以调用TestService的公共方法,比如调用其getRandomNumber方法获得随机数。

总结一下调用bindService之后发生的事情: 
client 执行 bindService -> 
如果Service不存在,Service 执行 onCreate -> 
如果没有执行过onBind,Service 执行 onBind -> 
client的实例ServiceConnection 执行 onServiceConnected

在执行了bindService之后,一共有一个client连接到了TestService,即ActivityA,每次client在调用了unbindService方法之后,该client会与Service解除绑定,在与某个client解除绑定之后,Service会检测是否还有其他的client与其连接绑定,如果没有其他任何client与其处于连接状态,那么Service会执行onUnbind方法,然后执行onDestroy方法,最终销毁自己。当ActivityA执行unbindService的时候,唯一的一个client与TestService解除了绑定的关系,TestService就执行了onUnbind方法,进而执行onDestroy方法。

总结一下调用unbindService之后发生的事情: 
client 执行 unbindService -> 
client 与 Service 解除绑定连接状态 -> 
Service 检测是否还有其他client与其连接,如果没有 -> 
Service 执行onUnbind -> 
Service 执行onDestroy

测试流程B

我们在测试完第一种流程后,关掉App,重启App,进行第二种测试流程。 
该测试也只涉及ActivityA,不涉及ActivityB。首先先点击ActivityA中的“bindService”按钮,然后点击”Finish”按钮,输出结果如下图所示: 

在该测试中,我们首先通过点击”bindService”按钮,使得ActivityA绑定了TestService,但是我们没有调用unbindService,而是直接通过调用“Finish”按钮让ActivityA直接销毁,通过上面的输出结果我们可以看到,在ActivityA销毁的时候,执行了ActivityA的onDestroy回调方法,之后TestService依次执行了onUnbind、onDestroy回调方法,TestService销毁。client与Service通过bindService连接起来之后,如果client销毁,那么client会自动与Service解除绑定,相当于在destroy之前会执行unbindService,在ActivityA销毁之后,ActivityA与Service解除了绑定,此时再没有client与Service处于连接绑定状态,这样Service就会执行onUnbind回调方法,表示没有client和我玩了,最后执行onDestroy回调方法。

测试流程C

我们在之前的两次测试流程中都只涉及ActivtityA,本测试流程会同时涉及ActivityA以及ActivityB。 
首先关掉App,重启App,按照以下步骤测试: 
1. 点击ActivityA中的”bindService”按钮 
2. 点击ActivityA中的”start ActivityB”按钮,界面切换到ActivityB 
3. 点击ActivityB中的”bindService”按钮 
4. 点击ActivityB中的”unbindService”按钮 
5. 点击ActivityB中的”Finish”按钮 
6. 点击ActivityA中的”unbindService”按钮

LogCat输出结果如下: 

下面我们依次分析每一步产生的影响,以便于完整地理解通过bindService启动的Service的生命周期:

  1. 点击ActivityA中的”bindService”按钮 
    由于初始情况下TestService实例不存在,也就是TestService没有运行。第一次调用bindService会实例化TestService,然后会执行其onBind方法,得到IBinder类型的实例,然后将其作为参数传入ActivityA的ServiceConnection的onServiceConnected方法中,标志着ActivityA与TestService建立了绑定连接,此时只有ActivityA这一个客户端client与TestService绑定。

  2. 点击ActivityA中的”start ActivityB”按钮,界面切换到ActivityB

  3. 点击ActivityB中的”bindService”按钮 
    由于TestService已经处于运行状态,所以ActivityB调用bindService时,不会重新创建TestService的实例,所以也不会执行TestService的onCreate回调方法,由于在ActivityA执行bindService的时候就已经执行了TestService的onBind回调方法而获取IBinder实例,并且该IBinder实例在所有的client之间是共享的,所以当ActivityB执行bindService的时候,不会执行其onBind回调方法,而是直接获取上次已经获取到的IBinder实例。并将其作为参数传入ActivityB的ServiceConnection的onServiceConnected方法中,标志着ActivityB与TestService建立了绑定连接,此时有两个客户单client(ActivityA和ActivityB)与TestService绑定。

  4. 点击ActivityB中的”unbindService”按钮 
    ActivityB执行了unbindService之后,ActivityB就与TestService解除了绑定。当没有任何client与Service处于绑定连接状态的时候,TestService才会执行onUnbind方法、onDestroy方法。但是由于此时还有ActivityA这个client与TestService处于绑定连接中,所以不会执行Service的onBind及onDestroy回调方法。

  5. 点击ActivityB中的”Finish”按钮 
    执行了ActivityB的finish方法后,ActivityB销毁了,界面返回到ActivityA

  6. 点击ActivityA中的”unbindService”按钮 
    ActivityA执行unbindService之后,ActivityA与TestService就解除绑定了,这样就没有客户端client与TestService相连,这时候Android会销毁TestService,在销毁前会先执行TestService的onUnbind方法,然后才会执行其onDestroy方法,这样TestService就销毁了。

bindService生命周期流程图

这里特别要说明的是,本文所提到的client指的是组件Component,比如某个Activity。如果在某一个Activity中,多次调用bindService方法连接Service,那么对于Service来说,这个Activity也只是一个client,而不是多个client。

最后我们将bindService启动的Service的生命周期总结为如下的流程图:



3、同时使用startService启动服务,bindService绑定服务的生命周期

例子一:按顺序1,2,3,4执行

(1)startServic:调用onCreate()->onStartCommand()

(2)bindService:调用onBind()

(3)stopService:没有调用onDestory()    Service仍然在运行!

(4)unbindService:调用onUnbind()->onDestory()    此时Service关闭!

例子二:将例子一3,4调换

(1)startServic:调用onCreate()->onStartCommand()

(2)bindService:调用onBind()

(3)unbindService:调用onUnbind()    Service仍然在运行!

(4)stopService:调用onDestory()     此时Service才关闭!

从上面的微妙变化,我们可以得出一个结论: 停止服务 销毁服务 是两个 不同的概念 ,虽然我们调用了stopService去停止服务,但是服务仍然木有销毁,依然坚挺的运行着。直至我们调用了onUnbind,与Service关联的client都解绑以后,Android系统才调用onDestroy将其销毁。

Why?我们来看官方的解释:

Note that if a stopped service still has ServiceConnection objects bound to it with the BIND_AUTO_CREATE set, it will not be destroyed until all of these bindings are removed.

总结:若被停止的服务依然有ServiceConnection 与其绑定,则服务不能销毁,直至我们把所有ServiceConnection 解绑

相应的,例子二当我们使用onUnbind去解绑后,服务依然运行,直至用户调用stopService,Service才可销毁。

Why?我们来看官方的解释:

When the last client unbinds from the service, the system destroys the service (unless the service was also started by startService()).

总结:当所有ServiceConnection 解绑后,系统会自动销毁服务。注意括号里面的内容:不包括同时用startService()启动的情况。此时,我们不得不再调用一次stopService来销毁它

给大家分享官方的一张图,更直观一些:









更多相关文章

  1. android Bundle saveInsanceState
  2. 解决Android(安卓)5.0以上版本Button自带阴影效果的方法
  3. Android(安卓)自定义 dialog
  4. android 重要组件之一activity,及进程间的通信
  5. [置顶] Android(安卓)Studio快捷键
  6. 屏幕触点
  7. 关于Activity的少许细节
  8. Android高手进阶教程(九)之----Android(安卓)Handler的使用!
  9. Android中如何获取字符或者字符串的宽度

随机推荐

  1. android页面跳转实现
  2. Android(安卓)ProgressDialog 进度条对话
  3. Android(安卓)网络与数据存储
  4. android中Sha256加密算法
  5. Android(安卓)网络视频播放
  6. Best practices in Android(安卓)develop
  7. Android(安卓)DatePickerDialog和TimePic
  8. android sdk开源中国网址
  9. android 对话框大全
  10. Android(安卓)菜单栏菜单功能