四大组件-Service

79 阅读10分钟

为什么需要Service?

  • 应用沙盒机制:每个应用独立进程运行
  • 主线程限制:UI 操作必须在主线程,耗时操作会导致 ANR
  • 生命周期管理:组件(Activity)生命周期短暂且不可预测
  • 跨应用通信需求:应用间需要安全可靠的数据共享

Service 需要解决的核心问题

  1. 后台任务可靠持续执行
  • 保证用户退出界面后任务不中断
  • 如:音乐播放、文件下载、位置追踪
  1. 进程优先级管理
  • 提升应用进程等级,避免被系统过早回收
  • 前台服务提供更高的存活概率
  1. 跨应用通信
  • 安全地共享功能和数据
  • 构建应用生态系统

一、Service 概述

1.1 什么是 Service?

  • 定义:Android四大组件之一,用于在后台执行长时间运行操作,不提供用户界面
  • 特点:
    1. 运行在主线程(默认),需自行创建子线程执行耗时任务
    2. 可被其他应用组件启动或绑定
    3. 可独立运行,即使启动它的组件被销毁
    4. 优先级低于Activity,但高于普通线程

1.2 Service vs Thread

对比项ServiceThread
生命周期有完整生命周期简单运行/结束
系统管理系统管理,不易被杀死应用管理,易被回收
跨进程支持跨进程通信不支持
优先级较高,不易被回收较低,易被回收

二、Service 类型

2.1 按启动方式分类

类型启动方式生命周期特点
Started ServicestartService()独立于启动组件执行单一任务,不返回结果
Bound ServicebindService()依赖于绑定组件提供客户端-服务器接口
混合型两者结合两种特性先启动后绑定,需同时停止和解绑

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_COMPATIBILITYSTART_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 不启动

检查点:

  1. AndroidManifest是否注册
  2. 是否在正确位置调用startService()
  3. Android 8.0+是否使用startForegroundService()
  4. 是否有权限问题

13.2 Service 被杀死

解决方案:

  1. 使用前台服务
  2. 设置START_STICKY或START_REDELIVER_INTENT
  3. 使用startForeground()提高优先级
  4. 监听系统广播,重新启动服务

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 核心概念

  1. Service是Android四大组件之一,用于后台执行长时间任务
  2. 三种主要类型:启动服务、绑定服务、前台服务
  3. 生命周期严格管理,需正确实现各回调方法
  4. 默认运行在主线程,耗时操作需自行创建线程

14.2 使用建议

  1. 简单任务用Thread,持久后台用Service
  2. Android 8.0+优先使用前台服务
  3. 绑定服务要及时解绑,避免内存泄漏
  4. 跨进程通信用AIDL,应用内通信用LocalBroadcast

14.3 现代替代方案

· 简单后台任务:Thread + Handler · 可延迟任务:WorkManager · 定时任务:AlarmManager + BroadcastReceiver · 需要用户感知:前台服务

14.4 版本适配重点

· Android 8.0+:后台服务限制,必须使用前台服务 · Android 9.0+:前台服务需要权限 · Android 12.0+:前台服务启动更严格限制

掌握Service需要理解其生命周期、线程管理和系统限制,在实际开发中应根据具体需求选择合适的实现方式,并注意版本兼容性问题。