Service 生命周期

Service 没有界面,它的生命周期完全由启动方式决定:startService 与 bindService 走两条不同的路径,
而且两条路径可以同时存在、互不抵消。启动方式的细节见 Service 启动方式。

1. 两条路径全景

graph TD
    A[startService] --> C[onCreate]
    B[bindService] --> C
    C --> D[onStartCommand]
    D -- 每次 startService 都回调 --> D
    D -- stopService / stopSelf --> E[onDestroy]
    D -- 前台服务类型额度用完 --> T[onTimeout]
    T -- 几秒内必须停止 --> E
    C --> F[onBind]
    F -- 只有第一个客户端触发 --> G[客户端已连接]
    G -- 全部 unBindService --> H[onUnbind]
    H -- onUnbind 返回 true 后再绑定 --> I[onRebind]
    H --> E

onCreate 是两条路径共用的入口,一个 Service 实例只走一次。

2. 回调详解

onCreate

onStartCommand(Intent, flags, startId)

返回值 被杀后行为 适用场景
START_STICKY 重建服务并回调 onStartCommand,但 Intent 为 null 不依赖启动参数的常驻服务(播放器、监听)
START_NOT_STICKY 不重建,除非期间又有新的启动请求 任务型服务(跑完就结束)
START_REDELIVER_INTENT 重建并重新投递最后一个 Intent 需要参数才能继续的任务(下载)
START_STICKY_COMPATIBILITY 兼容旧版本,不保证重建 基本不用

onTimeout(int) / onTimeout(int, int)

onBind(Intent)

onUnbind(Intent)

onRebind(Intent)

onDestroy

3. 启动 / 停止的组合规则

操作 回调 说明
startService(首次) onCreate → onStartCommand
startService(再次) onStartCommand onCreate 不再调用
stopService / stopSelf onDestroy 前提:没有客户端还绑着
bindService(首个客户端) onCreate → onBind
bindService(后续客户端) 无回调 直接用同一个 IBinder
unbindService(还有客户端) 无回调 服务继续运行
unbindService(最后一个) onUnbind → onDestroy 前提:没有被 startService 启动过

销毁条件只有一条:既没有任何客户端绑定,也不是被 startService 启动的。

混用时有两个必须记住的结论:

4. 进程优先级:Service 对存活的影响

服务形态 进程重要性 被杀概率
前台服务(startForeground) 仅次于可见进程 低(内存极紧张时仍可能被杀)
绑定服务(客户端在前台) 不低于客户端 较低
启动式服务(startService) 服务进程 中
纯后台(无任何活动组件) 缓存进程 高

5. 线程模型与 ANR

6. 常见坑

  1. 以为 onCreate 每次 startService 都会调用 —— 只有第一次
  2. 以为 onStartCommand 只会调用一次 —— 每次启动请求都会调用
  3. stopSelf() 顺手停掉了刚进来的新任务 —— 应该用 stopSelf(startId)
  4. START_REDELIVER_INTENT 配 stopSelf() —— 待重新投递的 Intent 会丢
  5. 在服务回调里直接做耗时操作 —— 主线程,照样 ANR
  6. 忘了 unbindService —— ServiceConnection 泄漏 Activity(在 onStop 或 onDestroy 里解绑)
  7. 用 onDestroy 保存关键数据 —— 进程被杀时不会执行
  8. 用 stopService 停"绑定中的服务" —— 停不掉,先确认没有客户端绑定
  9. 靠 START_STICKY 做保活 —— 重建时 Intent 为 null,而且会被后台限制、Doze 反复压制,别把它当保活方案
  10. 以为 onStartCommand 被废弃了 —— 没有。被废弃的是 IntentService(onHandleIntent),后台任务改用 WorkManager
  11. 没实现 onTimeout —— 前台服务类型额度用完后应用会崩(shortService 是 ANR),而宽限期只有几秒