Service虽然常被叫做后台服务,但它的代码运行在主线程。如果直接在onStartCommand里做文件下载、网络请求或数据库写入,界面会卡顿甚至ANR。正确做法是把耗时逻辑交给子线程、线程池或使用专门的工作线程组件。Service真正解决的问题不是异步,而是让系统知道应用有任务需要继续运行,即使界面被关闭,进程的优先级也会得到提升。先来看两种经典启动方式。

一、Service的两种启动模式:started与bound
started服务由Context.startService触发,启动后独立于组件存在。即使启动它的Activity销毁,服务仍会继续运行,直到调用stopService或服务自身调用stopSelf。典型场景包括后台音乐播放、文件上传和定时任务。此时服务的onBind可以返回null,因为不需要与调用方建立连接。
bound服务由Context.bindService触发,调用方可以获得一个IBinder接口进行跨组件通信。绑定方销毁后,系统会自动解除绑定,服务在没有其他启动或绑定状态时会销毁。典型场景是Activity需要实时获取Service内部状态,例如秒表计时、下载进度、音乐控制条。下面是两种服务的简单实现:
public class StartedService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 不要在这里直接做耗时操作
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
上面的StartedService只负责持续运行,所有工作都应该交给内部线程。onStartCommand的返回值决定系统在服务被杀死后的重建策略:START_STICKY会尝试重启服务,但Intent可能为空;START_NOT_STICKY不会主动重启;START_REDELIVER_INTENT会重启并重新传递最后一个Intent。
二、生命周期回调顺序与混合启动
理解生命周期需要区分纯启动、纯绑定、启动加绑定三种情况。纯启动时,回调顺序是onCreate、onStartCommand、onDestroy。纯绑定时,顺序是onCreate、onBind、onUnbind、onDestroy。启动加绑定时,调用startService再bindService后,服务不会被stopService立即销毁,而是要等所有绑定解除。换句话说,unbind不会结束由startService启动的服务,只有stopService或stopSelf才能让它进入销毁流程。
onCreate适合完成一次性的初始化,比如创建线程池、注册广播接收器。onStartCommand适合解析Intent指令,不同类型的指令可以在这里分发。onBind只在第一次绑定连接时调用,之后重复绑定会直接复用同一个IBinder。onUnbind用于清理与绑定方相关的数据,onDestroy则用于释放所有资源,包括线程、定时器、注册的监听器。
混合模式很容易被误用。比如一个音乐播放器既希望后台播放,又希望Activity能控制播放状态。此时可以先startService保证服务存活,再bindService获取控制接口。Activity退出时调用unbindService,服务不会停止,音乐继续播放。只有用户真正点击停止,服务才调用stopSelf。这个组合能同时兼顾长驻后台与实时通信。
三、前台服务与后台执行限制
普通后台服务的进程优先级较低,长时间运行容易被系统回收。前台服务通过调用startForeground并显示一条常驻通知,可以让服务优先级接近前台Activity。音乐播放器、导航、运动记录等用户可感知的任务适合使用前台服务。从Android 8.0开始,后台启动服务受到严格限制,如果应用处于后台状态调用startService会抛出IllegalStateException,必须改用startForegroundService,并在service启动后5秒内调用startForeground。
public class ForegroundService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Notification notification = new NotificationCompat.Builder(this, "channel_id")
.setContentTitle("前台服务运行中")
.setContentText("正在执行任务")
.setSmallIcon(android.R.drawable.ic_media_play)
.build();
startForeground(1001, notification);
return START_NOT_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
"channel_id",
"服务通知",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) {
manager.createNotificationChannel(channel);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
如果忘记在5秒内调用startForeground,系统会直接抛出异常或让应用崩溃,这是前台服务最常见的坑。另外,Android 13要求为前台服务声明特定类型,例如mediaPlayback、location、dataSync等,并申请对应权限。如果目标是Android 14及以上,还需要在Manifest中明确foregroundServiceType属性。不要为了保持进程存活而滥用前台服务,因为它会持续显示通知,消耗电量和用户信任。
对于不需要用户感知、但需要在后台可靠执行的任务,IntentService曾是一个简单方案。它在内部维护HandlerThread和工作线程,onHandleIntent在子线程执行,任务结束后自动停止。不过IntentService已经被标记为弃用,官方推荐使用WorkManager或JobIntentService,因为它们在省电、任务约束和系统重启后的持久化方面表现更好。
四、绑定服务通信:Binder、Messenger与AIDL怎么选
当Activity需要调用Service内部方法时,最常见的方式是在Service中返回一个继承Binder的内部类。调用方在ServiceConnection的onServiceConnected回调中获得Binder实例,再拿到Service引用后直接调用公共方法。这种方案简单直接,但要求调用方和服务运行在同一个进程,属于进程内通信。
public class BoundService extends Service {
private final IBinder binder = new LocalBinder();
public class LocalBinder extends Binder {
BoundService getService() {
return BoundService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public String getCurrentStatus() {
return "running";
}
}
如果需要跨进程通信,可以使用Messenger或AIDL。Messenger基于Message和Handler,底层使用Binder实现,适合简单的请求-响应模式,不需要处理复杂的多线程同步。AIDL则适合需要并发调用、数据类型丰富、接口稳定的场景,但需要手动处理线程安全。另一个常被忽略的问题是绑定连接泄漏:如果Activity在destroy时没有调用unbindService,会导致Service连接泄漏,系统会打印警告日志,甚至影响组件回收。务必把unbindService放在onStop或onDestroy中,与bindService成对出现。
结合生命周期来看,bound服务不适合作为长期后台任务的唯一手段,因为绑定方退出时服务会销毁。正确做法是根据业务特点选择:进程内简单控制用Binder,进程间简单通信用Messenger,复杂RPC用AIDL,可靠后台任务用WorkManager。
Android Service服务生命周期前台服务修改时间:2026-09-17 18:00:18