Service, 四大组件之一, 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件. 比如播放音乐, 下载文件等.
请注意, 虽然是后台执行任务, 但是 Service 是运行在主线程的! 如果要执行耗时任务, 最好手动创建新线程或者直接使用 IntentService
. (参考 IntentService 学习笔记).
两种启动方式
- 启动/停止- startService/stopService
- 绑定/解绑 - bindService/unbindService
区别
-
startService 只是启动服务, 启动它的组件(如 Activity)和服务并没有关联, 只有当服务调用 stopSelf()
或者其他组件调用 stopService()
时服务才会终止.
-
bindService 方法启动服务, 其它组件可以通过回调获取服务的代理对象和服务交互, 而这两方也进行了绑定, 当启动方销毁时, 服务也会自动进行 unBind
操作, 当发现所有绑定都进行了 unBind
时才会销毁服务.
生命周期
通过 startService 与 bindService 两种方式启动的 Service 的生命周期
启动服务
如何使用
创建服务类
继承 Service 类并覆写 onCreate()
onStartCommand()
onDestroy()
三个方法
注册服务
AndroidManifest.xml 里注册服务类.
- enabled: 是否能被系统实例化
- exported: 其他应用的组件是否能跟它交互, false表示私有只能自己应用使用, true表示可以被其他应用调起
启动服务
停止服务
通过外部组件:
或者通过服务自身
如果不调用 stopService
或者 stopSelf
, 直接关掉 Activity 对服务没影响, 因为两者的生命周期没有关联.
onStartCommand 返回值
onStartCommand()
方法返回整型数来描述系统应该如何在服务终止的情况下继续运行服务.
返回的值必须是以下常量之一:
如果服务在开始后 (onStartCommand()
返回后) 被终止, 比如内存不足, 然后会保持已开始状态 (started state), 但是并不保留接收的 intent. 稍后当系统有足够内存时会自己尝试重新创建服务. 因为服务仍处于已开始状态, 所以重建后会调用 onStartCommand()
方法. 但是除非此时有挂起的 intent 要启动服务, 不然传递的 intent 为 null. 使用此方式需要在代码中考虑处理 null 的情况.
该模式主要用于可以在任意的时间段显示的开始和结束服务, 比如后台的音乐播放服务.
如果服务在开始后 (onStartCommand()
返回后) 被终止, 但是不会保持已开始状态. 系统也不会再自建该服务. 只能通过显示的调用 startService(Intent)
来重新创建服务. 这是最安全的选项, 可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务.
- START_REDELIVER_INTENT
如果服务在开始后 (
onStartCommand()
返回后) 被终止, 则会重建服务, 并且传入最后一个接收的 intent 到 onStartCommand()
. 这适用于主动执行应该立即恢复的服务(例如下载文件).
小结:
START_STICKY
, START_REDELIVER_INTENT
会重启服务
START_STICKY
会传递 null 的 intent
START_REDELIVER_INTENT
会传递最后一个 intent
绑定服务
通过 onBind()
方法启动的service则会在 onCreate()
方法之后调用 onBind()
方法, 该方法返回一个 Binder
对象, 与该服务绑定的组件一般是通过返回的这个 Binder
对象与服务进行通信.
当所有与该服务绑定的组件分别都调用 unBindService()
后, 该服务才会被销毁
如何使用
创建服务类
注册服务
同 startService
一样需要在 AndroidManifest.xml 里进行注册.
创建 ServiceConnection 实例
在调用 onBind()
方法时需要传入一个 ServiceConnection
对象:
可以看到 onServiceConnected()
方法中有一个 IBinder
对象, 这个 IBinder
对象即为 Service 中 onBind()
方法返回的对象.
绑定服务
注意:
- 当你的 activity 需要在可见时才需要同服务交互则需要在activity的
onStart()
中绑定服务, 并在 onStop()
方法中解除绑定。
- 若当在 activity 在后台时仍需要与服务交互, 则需要在
onCreate()
方法中绑定, 并在 onDestory()
方法中解除绑定.
解除绑服务
实例
创建服务类
在 MainActivity 中绑定服务:
Intent intent = new Intent(this, BindService.class);
bindService(intent, conn, Service.BIND_AUTO_CREATE);
常见问题
- Service的 onCreate 回调函数可以做耗时的操作吗?
不行. Service 是在主线程中调用的, 耗时操作会阻塞UI. 可以使用创建一个新的线程或者使用 IntentService
.
见上文
参考