一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
前言
最近项目在处理多进程的问题,发现很多关于Service的基础有点模糊了,而且近几个版本官方对Service做了很多限制调整,也没有及时整理,这里做一个简单的记录。
Service 简介
Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。
Service 分类
- 前台服务:前台执行用户能注意的操作任务,即使用户停止与应用的交互,前台服务仍会继续运行。前台服务必须调用通知(Notification),让服务以显式的方式呈现给用户,如音乐播放等。
- 后台服务:后台执行用户无法直接关注的操作任务,如业务计算等。在
Android 8.0之后对其进行了相应的限制。- 应用进入后台之后,Service会持续运行数分钟,时间窗结束之后,应用会进入空闲状态,系统会停止应用的后台Service,服务调用
stopSelf()。 - 系统不允许后台应用创建后台Service,但可以设置服务为前台服务,调用
startForegroundService(),但需要注意5秒内需要调用startForeground()方法以显示新 Service 的用户可见通知。 如果应用在此时间限制内未调用 startForeground(),则系统将停止此 Service 并声明此应用为ANR。
- 应用进入后台之后,Service会持续运行数分钟,时间窗结束之后,应用会进入空闲状态,系统会停止应用的后台Service,服务调用
- 绑定服务:当应用组件通过调用 bindService() 绑定到服务时,服务即处于绑定状态。绑定服务会提供客户端-服务器接口,以便组件与服务进行交互、发送请求、接收结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
Service使用
Service子类
class MultiProcessService: Service() {
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
** 清单文件**
<service android:name=".MultiProcessService"
android:exported="false"
/>
Service启动方式
startService方式
val intent = Intent(this, MultiProcessService::class.java)
startService(intent)
- 当service首次启动,调用
startService(intent)时,先回调onCreate(),再回调onStartCommand();如果不是首次启动,直接回调onStartCommand(); - 当服务自身调用
stopSelf()或者应用组件stopService()后,会执行onDestroy(),此时Service生命周期结束。
注意:无论调用多少次startService,服务都会回调onStartCommand(),只有首次实例化才会回调onCreate(),如果不调用stopSelf()或者stopService()服务都会一直存活。
bindService方式
这种方式相对会复杂一些,需要定义用以服务交互的IBinder对象和用以监控服务连接状态的ServiceConnection实现。
class MultiProcessService : Service() {
override fun onBind(intent: Intent): IBinder = MultiProcessBinder()
inner class MultiProcessBinder : Binder() {
//.....
}
}
class MultiProcessActivity:Activity(){
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
//当服务绑定成功后或中断后重启,服务会回调该方法
}
override fun onServiceDisconnected(arg0: ComponentName) {
// 当服务异常终止时会调用。unbindService时不会调用
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(this, MultiProcessService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
}
- 通过bindService方式绑定的Service,如果当前没有对象与Service绑定,Service生命周期结束,这个过程包括绑定对象被销毁,或者主动掉调用unbindService()
注意:bindService()调用多次,如果组件与Service已经成功绑定后,不会多次返回ServiceConnection中的回调方法。
startService和bindService同时调用
两者可以同时启动Service,执行流程是按各自生命周期方法执行,需要注意的是这种情况下Service要回调onDestroy(),需要stopService和unbindService分别执行。