一、Service 两大类型
1. Started Service(启动服务)
startService(intent) 开启,一旦启动独立长期运行,与页面解绑,主动调用 stopSelf() / stopService() 才销毁。适用:后台上传、定时同步、日志上报、离线缓存。
2. Bound Service(绑定服务)
bindService(intent, connection, flags) 绑定,和调用方生命周期绑定,所有客户端全部 unbind 后服务销毁。适用:跨进程通信、频繁交互(如播放器控制、DataCenter 数据代理),对应你之前 ContentProvider.call 同类 IPC 场景。
3. 混合模式(start + bind 同时使用)
同时调用 startService + bindService:必须同时执行 stopService + 全部 unbind,服务才会销毁。
4. 前台服务 Foreground Service
Started Service 改造,弹出系统通知,不会被系统轻易杀死,如音乐播放、导航。
5. IntentService(废弃,API30+ 推荐 WorkManager / Coroutine)
内部单一线程自动处理任务,执行完自动销毁;已标记过时,不推荐新项目使用。
二、Service 全部生命周期方法(按执行顺序)
完整列表(生命周期回调,全部重写入口)
Service 原生全部回调方法一共 6 个
onCreate()onStartCommand()onBind()onUnbind()onRebind()onDestroy()
逐个说明触发条件
- onCreate服务第一次实例化执行一次,不管 start /bind 只走一次。
- onStartCommand仅
startService()触发,每次启动都会调用。 - onBind仅第一次
bindService()触发,返回 IBinder。 - onUnbind所有客户端全部解绑时触发。
- onRebind解绑后再次绑定才会触发(前提 onUnbind 返回 true)。
- onDestroy服务最终销毁唯一回调,资源释放。
补充区分:不属于生命周期回调的方法
startForeground():普通业务 API,不是系统生命周期回调stopSelf()/stopSelf(startId):开发者主动调用停止,不是回调- AIDL 自定义接口方法:自己写的,不属于 Service 原生回调
三种场景实际执行到的回调数量
- 只 startService:用到 3 个 → onCreate、onStartCommand、onDestroy
- 只 bindService:用到 4 个 → onCreate、onBind、onUnbind、onDestroy
- start + bind 混合反复解绑重绑:6 个生命周期回调全部走完
通用全部回调(基础 Service)
1. onCreate()
- 调用时机:服务第一次创建时执行 1 次,多次 start/bind 不会重复调用
- 作用:初始化数据库、线程池、管理器、全局资源
kotlin
override fun onCreate() {
super.onCreate()
// 只执行一次初始化
}
2. onStartCommand(intent: Intent?, flags: Int, startId: Int)
仅 Started Service 触发,每次 startService 都会调用返回值决定系统杀后台后的重启策略:
START_STICKY:被杀后自动重启,intent 为 null(音乐播放器)START_NOT_STICKY:被杀不重启(一次性任务)START_REDELIVER_INTENT:被杀重启并重新传入原 Intent(断点续传)START_STICKY_COMPATIBILITY兼容低版本
kotlin
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 处理后台任务,建议协程/线程执行耗时操作
return START_NOT_STICKY
}
3. onBind(intent: Intent): IBinder?
仅 Bound Service 触发,第一次 bindService 调用返回 IBinder 对象,作为客户端跨进程通信的媒介
kotlin
// 内部Binder,同进程通信
inner class LocalBinder : Binder() {
fun getService(): DataCenterService = this@DataCenterService
}
private val binder = LocalBinder()
override fun onBind(intent: Intent): IBinder = binder
4. onRebind(intent: Intent?)
客户端全部解绑后,再次绑定服务时触发(仅混合模式生效)
5. onUnbind(intent: Intent?): Boolean
所有客户端全部 unbind 时调用返回 true → 下次绑定触发 onRebind;false 不会触发
6. onDestroy()
服务销毁前最后回调,释放资源、关闭线程、注销监听、停止通知无论启动 / 绑定模式,销毁必走此方法
kotlin
override fun onDestroy() {
super.onDestroy()
// 释放资源,防止内存泄漏
}
补充:前台服务专属方法
startForeground(notificationId, Notification)在 onStartCommand 调用,提升服务优先级,避免被系统回收;API26+ 必须配通知渠道。
三、两种服务完整生命周期流程
流程 1:单纯 StartService(启动服务)
onCreate()→ 2.onStartCommand()停止方式:调用stopSelf(startId)/stopService(intent)销毁:onDestroy()
多次 startService:只走 onStartCommand,不会重复 onCreate
流程 2:单纯 BindService(绑定服务)
onCreate()→ 2.onBind()全部客户端解绑:onUnbind()→onDestroy()
流程 3:混合 start + bind
- onCreate → onStartCommand → onBind解绑所有客户端:仅执行 onUnbind,服务不会销毁(因为 start 标记存在)必须手动 stopService 才会走到 onDestroy
四、完整代码示例
1. Started Service 示例(后台任务)
kotlin
class BackSyncService : Service() {
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 协程执行耗时同步
CoroutineScope(Dispatchers.IO).launch {
syncDataCenter()
// 任务完成自动停止服务
stopSelf(startId)
}
return START_NOT_STICKY
}
override fun onBind(intent: Intent): IBinder? = null
override fun onDestroy() {
super.onDestroy()
}
private fun syncDataCenter() {
// 同步接口逻辑
}
}
启动:
kotlin
val intent = Intent(context, BackSyncService::class.java)
context.startService(intent)
// 停止
context.stopService(intent)
2. Bound Service 示例(同进程交互)
kotlin
class DataCenterBindService : Service() {
inner class LocalBinder : Binder() {
fun getService(): DataCenterBindService = this@DataCenterBindService
}
private val binder = LocalBinder()
// 对外提供方法
fun queryResult(): DataCenterResult {
return DataCenterResult(0, "success", null)
}
override fun onCreate() {
super.onCreate()
}
override fun onBind(intent: Intent): IBinder = binder
override fun onUnbind(intent: Intent?): Boolean {
return true // 支持rebind
}
override fun onRebind(intent: Intent?) {
super.onRebind(intent)
}
override fun onDestroy() {
super.onDestroy()
}
}
客户端绑定调用:
kotlin
private var service: DataCenterBindService? = null
private val conn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, ibinder: IBinder?) {
val binder = ibinder as DataCenterBindService.LocalBinder
service = binder.getService()
// 调用服务方法
val res = service?.queryResult()
}
override fun onServiceDisconnected(name: ComponentName?) {
service = null
}
}
// 绑定
val intent = Intent(this, DataCenterBindService::class.java)
bindService(intent, conn, Context.BIND_AUTO_CREATE)
// 解绑(页面销毁必须调用,否则内存泄漏)
unbindService(conn)
3. 前台服务片段
kotlin
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val channelId = "service_channel"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId, "后台同步", NotificationManager.IMPORTANCE_LOW)
val nm = getSystemService(NotificationManager::class.java)
nm.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(this, channelId)
.setContentTitle("数据同步中")
.setSmallIcon(R.mipmap.ic_launcher)
.build()
startForeground(1001, notification)
return START_STICKY
}
五、四大方法核心区别对比 Service vs ContentProvider
- Service:适合持续后台任务、双向方法调用、长连接;分启动 / 绑定两种模式,生命周期灵活
- ContentProvider:标准结构化数据共享,主打 CRUD 表格;call 仅作为补充扩展接口,不适合持续后台运行
六、关键注意点
-
Service 默认运行在主线程,耗时操作必须手动开子线程 / 协程;
-
bindService 必须配对 unbind,Activity/Fragment 销毁不解绑会内存泄漏;
-
Android8.0 禁止后台静默启动 Service,后台任务优先使用 WorkManager;
-
跨进程通信推荐两种方案:
- 频繁方法调用:Bound Service + AIDL
- 简单单次请求:ContentProvider.call
-
不要在 Service 做无限循环耗时任务,合理控制生命周期及时 stopSelf。