Service 生命周期

1. 生命周期路径

Service 的生命周期比 Activity 简单,但更容易出错,因为它可能在用户不可见时运行。

Service 主要有两条生命周期路径:

Started Service:startService() -> onCreate() -> onStartCommand() -> onDestroy()
Bound Service:bindService() -> onCreate() -> onBind() -> onUnbind() -> onDestroy()

如果一个 Service 同时被 start 和 bind,则两套规则会叠加。

2. Started Service 生命周期

启动流程:

flowchart TD
    A[startService] --> B{Service 是否已创建}
    B -- 否 --> C[onCreate]
    B -- 是 --> D[onStartCommand]
    C --> D[onStartCommand]
    D --> E[Service 运行]
    E --> F[stopSelf / stopService]
    F --> G[onDestroy]

特点:

  1. onCreate() 只在首次创建时调用一次。
  2. 每次调用 startService() 都会触发一次 onStartCommand()
  3. Started Service 不会因为启动它的 Activity 销毁而自动停止。
  4. 必须调用 stopSelf()stopService() 停止。
  5. 多次 startService() 后,不需要多次 stopService(),一次停止请求即可让 Service 停止,但并发处理多个 start 请求时要注意 stopSelf(startId)

3. Bound Service 生命周期

绑定流程:

flowchart TD
    A[bindService] --> B{Service 是否已创建}
    B -- 否 --> C[onCreate]
    B -- 是 --> D[onBind]
    C --> D[onBind]
    D --> E[Service 运行并与 Client 通信]
    E --> F[所有 Client unbindService]
    F --> G[onUnbind]
    G --> H[onDestroy]

特点:

  1. onBind() 返回 IBinder,客户端通过它与 Service 通信。
  2. 多个客户端可以同时绑定同一个 Service。
  3. 对同一个 Service,系统只会在第一个客户端绑定时调用 onBind() 创建通信通道,后续客户端通常复用同一个 IBinder
  4. 当所有客户端都解绑后,如果 Service 没有被 start,它会被销毁。
  5. Bound Service 不需要像 Started Service 那样主动调用 stopSelf()

4. 同时 startService 和 bindService

一个 Service 可以同时被启动和绑定:

startService() 让 Service 独立运行
bindService() 让客户端与 Service 通信

这种情况下:

操作 Service 是否停止
只调用 unbindService() 不停止,因为仍处于 started 状态
只调用 stopService() 不一定停止,因为仍有客户端绑定
stopService() + 所有客户端 unbindService() 才会停止
Service 内部 stopSelf() + 所有客户端解绑 会停止

示意图:

flowchart TD
    A[startService] --> B[onCreate]
    B --> C[onStartCommand]
    D[bindService] --> E[onBind]
    C --> F[Started 状态]
    E --> G[Bound 状态]
    F --> H{stopSelf/stopService?}
    G --> I{所有客户端 unbind?}
    H -- 是 --> J{仍有绑定?}
    I -- 是 --> K{仍是 started?}
    J -- 是 --> G
    J -- 否 --> L[onDestroy]
    K -- 是 --> F
    K -- 否 --> L[onDestroy]

5. onUnbind 与 onRebind

如果所有客户端解绑,系统会调用:

override fun onUnbind(intent: Intent?): Boolean {
    return true
}

如果 onUnbind() 返回 true,后续有客户端再次绑定时,会调用:

override fun onRebind(intent: Intent?) {
    super.onRebind(intent)
}

如果返回 false,再次绑定时通常不会调用 onRebind()

6. 生命周期中的资源清理

Service 中常见资源:

  • 子线程、线程池、协程。
  • BroadcastReceiver。
  • 传感器监听。
  • 定位回调。
  • Binder 连接。
  • MediaPlayer、Camera、Bluetooth 等硬件资源。

必须在 onDestroy() 中清理:

class LocationService : Service() {

    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

    override fun onDestroy() {
        scope.cancel()
        locationClient.removeLocationUpdates(callback)
        super.onDestroy()
    }
}

7. 常见错误

错误一:在 Service 里直接做耗时操作

// 错误:onStartCommand 默认在主线程
Thread.sleep(10_000)

正确做法:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    serviceScope.launch {
        doWork()
        stopSelf(startId)
    }
    return START_NOT_STICKY
}

错误二:绑定后不解绑

bindService() 后必须在合适时机调用 unbindService(),否则可能导致 Service 或 Activity 泄漏。

错误三:认为 Activity finish 后 Started Service 一定停止

Started Service 生命周期独立于启动它的组件。Activity 销毁后,它仍可能继续运行,直到显式停止或系统回收。

8. 面试回答模板

问题:Service 生命周期有哪些?

可以这样回答:

Service 有 Started 和 Bound 两条生命周期。Started Service 通过 startService 启动,首次创建走 onCreate,每次启动走 onStartCommand,需要 stopSelf 或 stopService 停止。Bound Service 通过 bindService 绑定,走 onCreate、onBind,客户端通过 IBinder 通信,所有客户端解绑后如果没有 started 状态就会销毁。如果一个 Service 同时被 start 和 bind,需要 stop 和 unbind 都完成后才会真正销毁。