安卓之service

发布于:2025-07-07 ⋅ 阅读:(18) ⋅ 点赞:(0)

在Android中,‌APK中的Service可以是前台服务或后台服务‌,具体由开发者决定其运行方式。‌

1、前台后台服务

一、前台服务 vs 后台服务的核心区别‌

特性‌ ‌前台服务‌ ‌后台服务‌
用户可见性‌ 必须显示持续通知(用户可见) 无通知,用户不可见
系统优先级‌ 高优先级,不易被系统回收 低优先级,易被系统回收(尤其内存不足时)
资源限制‌ 受较宽松的限制(如Android 8.0+允许长期运行) 受严格限制(如Android 8.0+限制后台执行时间)
典型用途‌ 音乐播放、导航、实时监控等关键任务 数据同步、日志收集等非关键任务
稳定性‌ 更稳定,适合长期运行 易被系统终止,适合短暂任务

二、系统对两者的处理策略‌

前台服务‌:

必须显示通知‌:通过startForeground()方法启动,并关联一个Notification。
高优先级‌:系统会尽量保留前台服务,避免其被回收。
兼容性‌:Android 8.0+要求前台服务必须声明FOREGROUND_SERVICE权限。

后台服务‌:

无通知‌:通过startService()启动,用户不可见。
严格限制‌:
Android 8.0+:后台服务运行时间受限(如10分钟内),超时后可能被终止。
Android 10+:进一步限制后台启动Activity的能力。
替代方案‌:
使用WorkManager处理延迟任务。
使用JobScheduler或AlarmManager调度周期性任务。

三、决定Service是前台还是后台的关键因素‌

启动方式‌:

前台服务‌:调用startForegroundService(),并在5秒内调用startForeground()显示通知。
后台服务‌:调用startService(),不显示通知。

系统资源管理‌:

前台服务会占用通知栏资源,但换取更高的稳定性。
后台服务不占用通知栏,但易被系统终止。

代码实现示例‌:

前台服务‌:

public class ForegroundService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Notification notification = new NotificationCompat.Builder(this, "channel_id")
            .setContentTitle("前台服务")
            .setContentText("正在运行")
            .setSmallIcon(R.drawable.ic_notification)
            .build();
        startForeground(1, notification); // 关键:转为前台服务
        return START_STICKY;
    }
}

后台服务‌:

public class BackgroundService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 执行后台任务(无通知)
        return START_NOT_STICKY; // 非关键任务,系统终止后不重启
    }
}

四、注意

关键任务用前台服务‌:
如音乐播放、实时定位等,需通过通知告知用户。
非关键任务用后台服务或替代方案‌:
如数据同步,可用WorkManager处理。

总结‌

前台服务‌:高优先级、用户可见、适合长期任务,但需显示通知。
后台服务‌:低优先级、用户不可见、适合短暂任务,但易被系统终止。
决定因素‌:启动方式(startForegroundService() vs startService())及系统资源管理策略。

2 、调试命令

一、查看是否存在这个服务依赖的apk

pm list packages | grep myapplication

二、 开始服务

前台服务

adb shell am startservice -n <包名>/<服务类全路径>

adb shell am startservice -n com.example.myapplication/.MyForegroundService

后台服务

adb shell am start-foreground-service -n com.example.myapplication/.MyForegroundService

三、结束服务

am stop-service -n com.example.myapplication/.MyForegroundService

四、打印服务状态

dumpsys activity services | grep "com.example.myapplication/.MyForegroundService"

注意:

当使用上面的 stop-service 的时候,可能不会打印

    public void onDestroy() {
        super.onDestroy();
        android.util.Log.e("MyService", "fln stop");
    }

因为会 命令会kill 掉

3、.继承 service 的子类

在 Android Service 的生命周期中,onCreate()onStartCommand()onDestroy()onBind() 的调用时机取决于服务的启动方式(启动模式绑定模式)。以下结合你的代码和 Android 机制进行详细说明:

一. 核心生命周期方法调用时机

(1) onCreate()
  • 调用时机
    仅当 Service 首次创建时调用一次(无论通过 startService()bindService() 启动)。若服务已存在,后续启动不会重复调用[citation:1][citation:3][citation:9]。
  • 用途
    初始化资源(如数据库、线程、通知渠道等)。
  • 代码示例
    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel(); // 初始化通知渠道(仅执行一次)
    }
    
(2) onStartCommand()
  • 调用时机
    每次通过 startService() 启动服务时调用(无论服务是否已存在)[citation:1][citation:9][citation:10]。
  • 用途
    执行后台任务(如下载、轮询),并返回 START_STICKY 等标志控制服务被杀死后的行为。
  • 代码示例
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 创建前台通知并启动线程
        startForeground(NOTIFICATION_ID, notification); 
        new Thread(() -> { /* 后台任务 */ }).start();
        return START_STICKY; // 服务被杀死后自动重启
    }
    
(3) onDestroy()
  • 调用时机
    服务被销毁时调用(主动调用 stopService()/stopSelf(),或绑定模式下所有客户端解绑)[citation:1][citation:3][citation:12]。
  • 用途
    释放资源(如停止线程、注销监听器)。
  • 代码示例
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("MyService", "Service stopped"); // 记录销毁日志
    }
    
(4) onBind()
  • 调用时机
    当组件通过 bindService() 绑定到服务时调用(若服务未运行,会先触发 onCreate())[citation:3][citation:11]。
  • 用途
    返回 IBinder 接口供客户端与服务交互(如跨进程通信)。
  • 代码示例
    @Override
    public IBinder onBind(Intent intent) {
        return null; // 你的代码未支持绑定模式,故返回 null
    }
    

二. 不同启动模式下的生命周期流程

启动模式(通过 startService()

在这里插入图片描述

绑定模式(通过 bindService()

在这里插入图片描述

⚠️ 注意:若服务同时通过 startService() 启动和 bindService() 绑定,需两者均终止(stopService() + 所有解绑)才会触发 onDestroy()[citation:3][citation:11]。

三 .Manifest 配合点

  1. 前台服务要求

    • 使用 startForeground() 需在 onStartCommand()5秒内 显示通知,否则 Android 8.0+ 会触发 ANR[citation:1]。
    • Android 14+ 需在 Manifest 声明 android:foregroundServiceType="dataSync" 及对应权限(如 FOREGROUND_SERVICE_DATA_SYNC)。
  2. 线程管理

    • onStartCommand() 中启动无限循环线程需谨慎:
      new Thread(() -> {
          while (true) { /* ... */ } // 需在 onDestroy() 中终止线程,否则内存泄漏!
      }).start();
      
  3. 服务重启策略

    • START_STICKY 适用于需自动重启的任务(如实时定位),但可能因频繁重启耗电[citation:9][citation:10]。
    • 非实时任务建议改用 WorkManager
  4. 注意点

  • onCreate():服务首次创建时初始化资源(一次性)。
  • onStartCommand():每次 startService() 调用时执行任务。
  • onDestroy():服务销毁时释放资源。
  • onBind():仅响应 bindService() 绑定请求(未使用可返回 null)。