为什么需要Service?
- 应用沙盒机制:每个应用独立进程运行
- 主线程限制:UI 操作必须在主线程,耗时操作会导致 ANR
- 生命周期管理:组件(Activity)生命周期短暂且不可预测
- 跨应用通信需求:应用间需要安全可靠的数据共享
Service 需要解决的核心问题
- 后台任务可靠持续执行
- 保证用户退出界面后任务不中断
- 如:音乐播放、文件下载、位置追踪
- 进程优先级管理
- 提升应用进程等级,避免被系统过早回收
- 前台服务提供更高的存活概率
- 跨应用通信
- 安全地共享功能和数据
- 构建应用生态系统
一、Service 概述
1.1 什么是 Service?
- 定义:Android四大组件之一,用于在后台执行长时间运行操作,不提供用户界面
- 特点:
- 运行在主线程(默认),需自行创建子线程执行耗时任务
- 可被其他应用组件启动或绑定
- 可独立运行,即使启动它的组件被销毁
- 优先级低于Activity,但高于普通线程
1.2 Service vs Thread
| 对比项 | Service | Thread |
|---|---|---|
| 生命周期 | 有完整生命周期 | 简单运行/结束 |
| 系统管理 | 系统管理,不易被杀死 | 应用管理,易被回收 |
| 跨进程 | 支持跨进程通信 | 不支持 |
| 优先级 | 较高,不易被回收 | 较低,易被回收 |
二、Service 类型
2.1 按启动方式分类
| 类型 | 启动方式 | 生命周期 | 特点 |
|---|---|---|---|
| Started Service | startService() | 独立于启动组件 | 执行单一任务,不返回结果 |
| Bound Service | bindService() | 依赖于绑定组件 | 提供客户端-服务器接口 |
| 混合型 | 两者结合 | 两种特性 | 先启动后绑定,需同时停止和解绑 |
2.2 按运行方式分类
| 类型 | 特点 | 使用场景 |
|---|---|---|
| 本地服务 | 与主进程同一进程 | 应用内部后台任务 |
| 远程服务 | 独立进程,需AIDL | 跨进程通信 |
| 前台服务 | 显示通知,优先级高 | 用户感知的后台任务 |
三、Service 生命周期
3.1 生命周期流程图
→ onCreate() → onStartCommand() → 运行
startService() ────────┘
→ onCreate() → onBind() → 客户端交互
bindService() ─────────┘ onUnbind() → onDestroy()
↙
stopService() / stopSelf() ────────┘
unbindService() ────────────────────┘
3.2 生命周期方法详解
public class MyService extends Service {
// 1. 创建服务时调用(仅一次)
@Override
public void onCreate() {
super.onCreate();
// 初始化资源
}
// 2. 每次startService()时调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 执行任务
// 返回值决定服务被杀死后的行为
return START_STICKY;
}
// 3. 绑定服务时调用
@Override
public IBinder onBind(Intent intent) {
// 返回IBinder接口,用于客户端通信
return new MyBinder();
}
// 4. 重新绑定时调用(仅当onUnbind()返回true)
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
// 5. 解绑时调用
@Override
public boolean onUnbind(Intent intent) {
return true; // true表示允许重新绑定
}
// 6. 销毁服务时调用
@Override
public void onDestroy() {
super.onDestroy();
// 清理资源
}
}
3.3 onStartCommand() 返回值
| 返回值 | 含义 | 适用场景 |
|---|---|---|
| START_STICKY | 服务被杀后重建,但不保留Intent | 媒体播放器等持久服务 |
| START_NOT_STICKY | 服务被杀后不自动重建 | 定时任务,可中断 |
| START_REDELIVER_INTENT | 服务被杀后重建,并重新传递Intent | 下载服务等需要恢复的任务 |
| START_STICKY_COMPATIBILITY | START_STICKY的兼容版本 | 低版本兼容 |
3.4 flags 参数
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// flags取值:
// START_FLAG_REDELIVERY: Intent是重新传递的(上次服务未完成)
// START_FLAG_RETRY: 上次启动尝试失败
}
四、Service 实现详解
4.1 Started Service(启动服务)
// 1. 定义服务
public class MyStartedService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null; // 启动服务不需要绑定
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 执行后台任务(注意:需在子线程执行耗时操作)
new Thread(() -> {
// 耗时任务
performTask();
// 任务完成后停止自己
stopSelf(startId);
}).start();
return START_STICKY;
}
}
// 2. 启动和停止服务
public class MainActivity extends AppCompatActivity {
private void startMyService() {
Intent intent = new Intent(this, MyStartedService.class);
intent.putExtra("data", "some data");
startService(intent); // 启动服务
}
private void stopMyService() {
Intent intent = new Intent(this, MyStartedService.class);
stopService(intent); // 停止服务
}
}
4.2 Bound Service(绑定服务)
// 1. 定义Binder
public class MyBoundService extends Service {
// 创建Binder
public class MyBinder extends Binder {
MyBoundService getService() {
return MyBoundService.this;
}
}
private final IBinder binder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return binder;
}
// 服务方法
public void doSomething() {
// 执行操作
}
public int getData() {
return 42;
}
}
// 2. 客户端绑定
public class MainActivity extends AppCompatActivity {
private MyBoundService mService;
private boolean isBound = false;
// ServiceConnection接口
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyBoundService.MyBinder binder = (MyBoundService.MyBinder) service;
mService = binder.getService();
isBound = true;
// 使用服务
mService.doSomething();
int data = mService.getData();
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
mService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 绑定服务
Intent intent = new Intent(this, MyBoundService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 解绑服务
if (isBound) {
unbindService(connection);
isBound = false;
}
}
}
4.3 绑定服务的绑定标志
| 标志 | 说明 |
|---|---|
| BIND_AUTO_CREATE | 绑定不存在时自动创建 |
| BIND_IMPORTANT | 服务对客户端很重要 |
| BIND_ABOVE_CLIENT | 服务优先级高于客户端 |
| BIND_ADJUST_WITH_ACTIVITY | 服务优先级随Activity调整 |
| BIND_WAIVE_PRIORITY | 放弃优先级调整 |
五、前台服务(Foreground Service)
5.1 前台服务实现
public class MyForegroundService extends Service {
private static final String CHANNEL_ID = "ForegroundServiceChannel";
private static final int NOTIFICATION_ID = 1;
@Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 创建通知
Notification notification = createNotification();
// 启动前台服务(Android 8.0+必须显示通知)
startForeground(NOTIFICATION_ID, notification);
// 执行任务
performForegroundTask();
return START_STICKY;
}
private void createNotificationChannel() {
// Android 8.0+ 需要创建通知渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
private Notification createNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE
);
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("前台服务运行中")
.setContentText("服务正在执行任务...")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.build();
}
}
5.2 AndroidManifest 权限
<!-- Android 9.0+ 需要前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Service声明 -->
<service
android:name=".MyForegroundService"
android:enabled="true"
android:exported="false" />
5.3 启动前台服务
// Android 8.0+ 需要使用 startForegroundService()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent serviceIntent = new Intent(this, MyForegroundService.class);
startForegroundService(serviceIntent);
} else {
Intent serviceIntent = new Intent(this, MyForegroundService.class);
startService(serviceIntent);
}
六、IntentService(已废弃,Android 8.0+)
6.1 原 IntentService 特点
// 原 IntentService 实现(已废弃)
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 在工作线程中执行任务
// 任务按顺序执行
// 任务完成后自动停止
}
}
6.2 替代方案:JobIntentService / WorkManager
// 使用 JobIntentService(兼容方案)
public class MyJobIntentService extends JobIntentService {
static final int JOB_ID = 1000;
static void enqueueWork(Context context, Intent work) {
enqueueWork(context, MyJobIntentService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// 在工作线程执行任务
}
}
// 推荐:使用 WorkManager(现代方案)
public class MyWorker extends Worker {
public MyWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
// 执行后台任务
return Result.success();
}
}
七、跨进程服务(AIDL)
7.1 AIDL 接口定义
// IMyService.aidl
package com.example;
interface IMyService {
int getData();
void setData(int data);
void registerCallback(IMyCallback callback);
void unregisterCallback(IMyCallback callback);
}
// IMyCallback.aidl
package com.example;
interface IMyCallback {
void onDataChanged(int newData);
}
7.2 服务端实现
public class MyRemoteService extends Service {
private int data = 0;
private List<IMyCallback> callbacks = new ArrayList<>();
private final IMyService.Stub binder = new IMyService.Stub() {
@Override
public int getData() {
return data;
}
@Override
public void setData(int newData) {
data = newData;
notifyCallbacks(newData);
}
@Override
public void registerCallback(IMyCallback callback) {
if (callback != null && !callbacks.contains(callback)) {
callbacks.add(callback);
}
}
@Override
public void unregisterCallback(IMyCallback callback) {
callbacks.remove(callback);
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private void notifyCallbacks(int newData) {
for (IMyCallback callback : callbacks) {
try {
callback.onDataChanged(newData);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
7.3 客户端调用
public class MainActivity extends AppCompatActivity {
private IMyService myService;
private boolean isBound = false;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = IMyService.Stub.asInterface(service);
isBound = true;
try {
int data = myService.getData();
myService.setData(42);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
myService = null;
}
};
private void bindRemoteService() {
Intent intent = new Intent();
intent.setComponent(new ComponentName(
"com.example.serviceapp",
"com.example.serviceapp.MyRemoteService"
));
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
}
八、Service 与线程管理
8.1 Service 中的多线程
public class ThreadedService extends Service {
private ExecutorService executorService;
private Handler mainHandler;
@Override
public void onCreate() {
super.onCreate();
// 创建线程池
executorService = Executors.newFixedThreadPool(4);
// 主线程Handler
mainHandler = new Handler(Looper.getMainLooper());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 在线程池执行任务
executorService.execute(() -> {
// 后台任务
String result = performLongRunningTask();
// 回到主线程更新UI
mainHandler.post(() -> {
// 可以发送广播或更新UI
sendResultBroadcast(result);
});
// 任务完成
stopSelf(startId);
});
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
// 关闭线程池
if (executorService != null) {
executorService.shutdown();
}
}
}
8.2 使用 HandlerThread
public class HandlerThreadService extends Service {
private HandlerThread handlerThread;
private Handler backgroundHandler;
private Handler mainHandler;
@Override
public void onCreate() {
super.onCreate();
// 创建后台线程
handlerThread = new HandlerThread("ServiceHandlerThread");
handlerThread.start();
// 后台线程Handler
backgroundHandler = new Handler(handlerThread.getLooper());
// 主线程Handler
mainHandler = new Handler(Looper.getMainLooper());
}
private void executeTask() {
backgroundHandler.post(() -> {
// 后台执行
String result = doWork();
// 回到主线程
mainHandler.post(() -> {
// 更新UI或通知
});
});
}
@Override
public void onDestroy() {
super.onDestroy();
if (handlerThread != null) {
handlerThread.quitSafely();
}
}
}
九、Service 通信方式
9.1 Broadcast 通信
// Service发送广播
private void sendProgressUpdate(int progress) {
Intent intent = new Intent("com.example.PROGRESS_UPDATE");
intent.putExtra("progress", progress);
sendBroadcast(intent);
}
// Activity接收广播
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int progress = intent.getIntExtra("progress", 0);
updateProgressBar(progress);
}
};
9.2 LocalBroadcast 通信
// Service中
LocalBroadcastManager.getInstance(this)
.sendBroadcast(intent);
// Activity中
LocalBroadcastManager.getInstance(this)
.registerReceiver(receiver, filter);
9.3 回调接口通信
// 定义回调接口
public interface ServiceCallback {
void onTaskCompleted(String result);
void onProgressUpdate(int progress);
}
// Service中管理回调
public class CallbackService extends Service {
private List<ServiceCallback> callbacks = new ArrayList<>();
public void registerCallback(ServiceCallback callback) {
if (!callbacks.contains(callback)) {
callbacks.add(callback);
}
}
public void unregisterCallback(ServiceCallback callback) {
callbacks.remove(callback);
}
private void notifyCallbacks() {
for (ServiceCallback callback : callbacks) {
callback.onProgressUpdate(progress);
}
}
}
十、Android 8.0+ 限制与适配
10.1 后台执行限制
Android版本 限制内容 解决方案 8.0+ 后台服务限制,应用进入后台后服务很快停止 使用前台服务 9.0+ 限制后台应用访问传感器、麦克风等 前台服务声明权限 10.0+ 限制后台启动Activity 使用全屏Intent或通知
10.2 前台服务适配
// 检查前台服务权限
private boolean hasForegroundServicePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.FOREGROUND_SERVICE
) == PackageManager.PERMISSION_GRANTED;
}
return true;
}
// 启动前台服务
private void startForegroundServiceSafely() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (hasForegroundServicePermission()) {
Intent serviceIntent = new Intent(this, MyForegroundService.class);
startForegroundService(serviceIntent);
} else {
// 请求权限
requestForegroundServicePermission();
}
} else {
Intent serviceIntent = new Intent(this, MyForegroundService.class);
startService(serviceIntent);
}
}
十一、最佳实践
11.1 性能优化
// 1. 使用线程池,避免频繁创建线程
private ExecutorService executorService = Executors.newCachedThreadPool();
// 2. 及时释放资源
@Override
public void onDestroy() {
super.onDestroy();
// 关闭数据库连接
// 取消网络请求
// 释放Bitmap内存
}
// 3. 使用WakeLock保持CPU运行(谨慎使用)
private void acquireWakeLock() {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"MyService::WakeLock"
);
wakeLock.acquire(10 * 60 * 1000); // 10分钟
// 任务完成后记得释放
// wakeLock.release();
}
11.2 内存管理
// 1. 避免内存泄漏
public class MyService extends Service {
private static MyService instance; // 错误:静态引用导致泄漏
// 正确做法:使用弱引用
private static WeakReference<MyService> weakReference;
}
11.3 错误处理
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
// 业务逻辑
performTask();
} catch (Exception e) {
// 记录错误日志
Log.e("MyService", "Task failed", e);
// 通知用户(可选)
sendErrorNotification(e.getMessage());
// 根据错误类型决定是否重试
if (shouldRetry(e)) {
return START_REDELIVER_INTENT;
} else {
return START_NOT_STICKY;
}
}
return START_STICKY;
}
十二、替代方案(现代Android开发)
12.1 WorkManager(推荐)
public class MyWorker extends Worker {
public MyWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
// 执行后台任务
try {
performTask();
return Result.success();
} catch (Exception e) {
return Result.retry(); // 或 failure()
}
}
}
// 使用
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
.setConstraints(
new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build();
WorkManager.getInstance(context).enqueue(myWorkRequest);
12.2 JobScheduler(Android 5.0+)
public class MyJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
// 在后台线程执行任务
new Thread(() -> {
performTask();
jobFinished(params, false); // 任务完成
}).start();
return true; // true表示任务在后台线程执行
}
@Override
public boolean onStopJob(JobParameters params) {
// 任务被中断
return true; // true表示需要重新调度
}
}
十三、常见问题与解决方案
13.1 Service 不启动
检查点:
- AndroidManifest是否注册
- 是否在正确位置调用startService()
- Android 8.0+是否使用startForegroundService()
- 是否有权限问题
13.2 Service 被杀死
解决方案:
- 使用前台服务
- 设置START_STICKY或START_REDELIVER_INTENT
- 使用startForeground()提高优先级
- 监听系统广播,重新启动服务
13.3 内存泄漏
// 常见泄漏点及修复
public class MainActivity extends AppCompatActivity {
// ❌ 错误:内部类持有Activity引用
private ServiceConnection connection = new ServiceConnection() {
// ...
};
// ✅ 正确:使用静态内部类+弱引用
private static class MyServiceConnection implements ServiceConnection {
private WeakReference<MainActivity> activityRef;
MyServiceConnection(MainActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MainActivity activity = activityRef.get();
if (activity != null) {
// 更新Activity
}
}
}
}
十四、总结要点
14.1 核心概念
- Service是Android四大组件之一,用于后台执行长时间任务
- 三种主要类型:启动服务、绑定服务、前台服务
- 生命周期严格管理,需正确实现各回调方法
- 默认运行在主线程,耗时操作需自行创建线程
14.2 使用建议
- 简单任务用Thread,持久后台用Service
- Android 8.0+优先使用前台服务
- 绑定服务要及时解绑,避免内存泄漏
- 跨进程通信用AIDL,应用内通信用LocalBroadcast
14.3 现代替代方案
· 简单后台任务:Thread + Handler · 可延迟任务:WorkManager · 定时任务:AlarmManager + BroadcastReceiver · 需要用户感知:前台服务
14.4 版本适配重点
· Android 8.0+:后台服务限制,必须使用前台服务 · Android 9.0+:前台服务需要权限 · Android 12.0+:前台服务启动更严格限制
掌握Service需要理解其生命周期、线程管理和系统限制,在实际开发中应根据具体需求选择合适的实现方式,并注意版本兼容性问题。