Service 属于 Android 四大组件之一,开启Service有两种不同的方式: startService 和 bindService。不同的开启方式, Service执行的生命周期方法也不同。
-
startService 开启服务时, 生命周期执行的方法依次是:
onCreate() ==> onStartCommand()
之后调用多次 startService ,onCreate 只有第一次会被执行而 onStartCommand 会执行多次
-
调用 stopService结束服务, 生命周期执行 onDestroy 方法. 多次调用 stopService 时, onDestroy 只有第一次会被执行。
-
bindService 绑定服务
//开启服务
Intent service = new Intent(this, MyService.class);
MyConnection conn = new MyConnection();
//第一个参数:Intent意图
//第二个参数:是一个接口,通过这个接口接收服务开启或者停止的消息,并且这个参数不能为null
//第三个参数:开启服务时的操作,BIND_AUTO_CREATE 代表自动创建 service
bindService(service, conn, BIND_AUTO_CREATE);
bindService 的方法参数需要一个 ServiceConnection 接口的实现类对象. 我们自己写一个 MyConnection 类, 并实现里面的方法。
class MyServerConnec implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected: ");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected: ");
}
}
-
bingService开启服务时, 根据 Service#onBind 的返回值是否为空, 有两种情况:
- onBind返回值是 null
@Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind: "); return null; }
调用bindService开启服务,生命周期执行的方法依次是:
2019-03-10 10:29:26.056 20362-20362/com.xforg.demo_service D/MyService: onCreate: 2019-03-10 10:29:26.058 20362-20362/com.xforg.demo_service D/MyService: onBind:
即使多次调用 bindService,onCreate 和 onBind 也只在第一次调用时被回调。
调用 unbindService 结束服务,生命周期执行 onDestroy 方法,并且 unbindService 方法只能调用一次,多次调用应用会抛出异常
使用时也要注意调用 unbindService 一定要确保服务已经开启,否则应用会抛出如下异常:
2019-03-10 10:38:56.759 20828-20828/com.xforg.demo_service E/AndroidRuntime: FATAL EXCEPTION: main Process: com.xforg.demo_service, PID: 20828 java.lang.IllegalArgumentException: Service not registered: com.xforg.demo_service.MainActivity$MyServerConnec@33ab3bb at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1562) at android.app.ContextImpl.unbindService(ContextImpl.java:1692)
-
onBind 返回值不为 null
那么我们就在自己写的 MyService 里创建一个内部类 myBinder,让它继承 Binder,并在 onBind 方法里返回 myBinder 的对象。
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: ");
return new myBinder();
}
class myBinder extends Binder{
public int add(int a, int b){
return a + b;
}
}
此时我们在 onServiceConnected时,做如下操作:
class MyServerConnec implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected: ");
myService = (MyService.myBinder) service;
int result = myService.add(1,2);
Log.d(TAG, "onServiceConnected: result is "+result);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected: ");
}
}
这时候调用 bindService 开启服务, 生命周期执行的方法依次是:onCreate() ==> onBind() ==> onServiceConnected()
2019-03-10 10:53:16.679 21687-21687/com.xforg.demo_service D/MainActivity: onServiceConnected:
2019-03-10 10:53:16.679 21687-21687/com.xforg.demo_service D/MainActivity: onServiceConnected: result is 3
调用多次 bindService ,onCreate、onBind、onServiceConnected 都只在第一次调用时被执行。
PS: 注意这里的 MyService 和 Activity 是在同一个进程中!!!!
-
startService 开启服务以后,与activity就没有关联,不受影响,独立运行。
-
bindService 绑定服务后, 与 activity 存在关联. 退出 activity 时必须调用 unbindService 方法, 否则会报 ServiceConnection 泄漏的错误。
2019-03-10 11:03:49.074 21687-21687/com.xforg.demo_service E/ActivityThread: Activity com.xforg.demo_service.MainActivity
has leaked ServiceConnection com.xforg.demo_service.MainActivity$MyServerConnec@ac35cd1 that was originally bound here
android.app.ServiceConnectionLeaked: Activity com.xforg.demo_service.MainActivity has leaked ServiceConnection com.xforg.demo_service.MainActivity$MyServerConnec@ac35cd1 that was originally bound here
at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1610)
当同一个服务用 startService 和 bindService 两种方式一同开启,没有先后顺序的要求,MyService 的 onCreate 只会执行一次。关闭服务需要 stopService 和 unbindService 都被调用, 也没有先后顺序的影响. MyService的 onDestroy 也只执行一次。但是如果只用一种方式关闭服务,不论是哪种关闭方式,onDestroy都不会被执行, 服务也不会被关闭。
ps:
Service的onCreate、onStartCommand、onDestory等全部生命周期方法都运行在UI线程,ServiceConnection里面的回调方法也是运行在UI线程
Service类有个生命周期方法叫 onStartCommand ,每次 startService 时都会回调此方法:
public int onStartCommand(Intent intent, int flags, int startId)
需要关注的是这个方法有一个整型的返回值, 它们将影响服务异常终止情况下重启服务时的行为
默认情况下, 当我们的服务因为系统内存吃紧或者其他原因被异常终止时, 系统会尝试在某个时刻重新启动服务.
- START_NOT_STICKY
如果系统在onStartCommand()方法返回之后杀死这个服务,那么直到接受到新的Intent对象,这个服务才会被重新创建。这是最安全的选项, 用来避免在不需要的时候运行你的服务。
- START_STICKY(系统的默认策略)
如果系统在onStartCommand()返回后杀死了这个服务,系统就会重新创建这个服务并且调用onStartCommand()方法,但是它不会重新传递 最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand()方法,在这个情况下,除非有一些被发送的Intent对象在 等待启动服务。这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。
- START_REDELIVER_INTENT
如果系统在onStartCommand()方法返回后杀死了这个服务, 系统就会重新创建了这个服务并且用发送给这个服务的最后的 Intent对象 调用了 onStartCommand()方法。任意等待中的 Intent 对象会依次被发送。这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。