Service 基础生命周期回顾:onCreate、onStartCommand、onDestroy 调用时机与返回标志

在深入前台服务之前,必须清晰掌握普通 Service 的三个核心生命周期方法:onCreate()、onStartCommand()、onDestroy()。前台的启动/停止行为完全基于这些方法,区别仅在于必须绑定一个前台通知。理解调用时机和返回标志,是避免服务被系统意外回收或重启混乱的基石。

生命周期方法调用时机调用次数典型用途
onCreate()首次通过 startService() 或 bindService() 创建 Service 时仅一次(除非 Service 被销毁后重新创建)初始化定时器、线程池、数据库连接、通知渠道等
onStartCommand()每次调用 startService() 时触发(如果 Service 已创建,跳过 onCreate() 直接进入此处)每次 start 都调用处理本次启动的 Intent、执行后台任务
onDestroy()调用 stopService() 或 stopSelf(),且系统决定真正销毁 Service 之前仅一次释放资源、关闭线程、取消通知、反注册广播
关键认知:前台服务与后台服务的生命周期方法完全一致。区别在于前台服务必须调用 startForeground() 并在 onStartCommand() 返回时保持通知可见,但 onCreate/onStartCommand/onDestroy 的调用时机规则不变。

onStartCommand 返回标志详解

onStartCommand() 必须返回一个整型常量,用于告知系统如果该 Service 因内存不足被系统杀死后,系统应该以何种行为恢复它。这是 Android Service 生命周期中极为特殊且常被误解的环节。

返回标志整型值行为说明典型场景
START_STICKY1Service 被杀后系统会尽力重新创建它,并传入 null 的 Intent 调用 onStartCommand()(即不恢复原 Intent)持续运行的任务(如音乐播放、位置追踪),无需恢复原始启动参数
START_NOT_STICKY2Service 被杀后系统不会自动重启,除非有新的 startService() 调用一次性任务(如上传单个文件),重启无意义
START_REDELIVER_INTENT3Service 被杀后系统会重新创建服务,并重新投递最后一个未完成的 Intent需要确保任务完整执行(如下载队列、支付确认)
START_STICKY_COMPATIBILITY0兼容模式,行为类似 START_STICKY 但不受 startId 序列管理,不推荐使用极低版本兼容(API 5 以下),现代开发应避免
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // 处理启动 Intent
    if (intent != null) {
        String action = intent.getAction();
        // 根据 action 执行不同任务
    }
    // 前台服务通常返回 START_STICKY 保证系统重启
    return START_STICKY;
}
实践要点:
  • 前台服务(Foreground Service)推荐使用 START_STICKY 或 START_REDELIVER_INTENT,因为前台通知表明用户期望该服务持续运行,系统重启后应尽量恢复。
  • 如果服务完全由前台通知驱动且任务可丢弃,可返回 START_NOT_STICKY 减少不必要的资源开销。
  • 切勿返回 START_STICKY_COMPATIBILITY,该标志在现代 Android 中行为不可预期。

完整生命周期调用顺序示例

以下代码片段展示了在普通 Service 中如何记录所有生命周期方法的调用日志,便于观察调用时机:

public class DemoService extends Service {
    private static final String TAG = "DemoService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: 服务创建");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: 收到启动请求,startId=" + startId);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: 服务销毁");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null; // 未绑定情况
    }
}

当依次执行 startService() → stopService() 时,日志输出如下:

D/DemoService: onCreate: 服务创建
D/DemoService: onStartCommand: 收到启动请求,startId=1
D/DemoService: onDestroy: 服务销毁

若连续调用两次 startService(),则 onCreate() 只调用一次:

D/DemoService: onCreate: 服务创建
D/DemoService: onStartCommand: 收到启动请求,startId=1
D/DemoService: onStartCommand: 收到启动请求,startId=2
陷阱提醒:如果 Service 已在运行,onCreate() 不会再次触发。这也意味着任何需要在 onStartCommand() 中重新初始化的逻辑(如重置定时器)必须写在 onStartCommand() 内部,不能依赖 onCreate() 重复执行。
Service 基础生命周期与返回标志影响流程 startService() 调用 onCreate() onStartCommand() START_STICKY START_NOT_STICKY START_REDELIVER_INTENT 杀进程后系统重新创建 并传入 null Intent 杀进程后不自动重启 等待下一次 startService() 杀进程后重新创建 并投递最后一个 Intent stopService() 触发 onDestroy()

上图清晰地展示了:当调用 startService() 后,系统首先调用 onCreate()(仅首次),然后每次都会进入 onStartCommand()。该方法的返回值决定了服务被系统杀死后的恢复策略。只有主动调用 stopService() 或 stopSelf() 时才会触发 onDestroy()。