安卓之service

在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(),不显示通知。

系统资源管理‌:

前台服务会占用通知栏资源,但换取更高的稳定性。

后台服务不占用通知栏,但易被系统终止。

代码实现示例‌:

前台服务‌:

java 复制代码
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;
    }
}

后台服务‌:

java 复制代码
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

bash 复制代码
pm list packages | grep myapplication

二、 开始服务

前台服务

bash 复制代码
adb shell am startservice -n <包名>/<服务类全路径>

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

后台服务

bash 复制代码
adb shell am start-foreground-service -n com.example.myapplication/.MyForegroundService

三、结束服务

bash 复制代码
am stop-service -n com.example.myapplication/.MyForegroundService

四、打印服务状态

bash 复制代码
dumpsys activity services | grep "com.example.myapplication/.MyForegroundService"

注意:

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

java 复制代码
    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]。

  • 用途
    初始化资源(如数据库、线程、通知渠道等)。

  • 代码示例

    java 复制代码
    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel(); // 初始化通知渠道(仅执行一次)
    }
(2) onStartCommand()
  • 调用时机
    每次通过 startService() 启动服务时调用(无论服务是否已存在)[citation:1][citation:9][citation:10]。

  • 用途
    执行后台任务(如下载、轮询),并返回 START_STICKY 等标志控制服务被杀死后的行为。

  • 代码示例

    java 复制代码
    @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]。

  • 用途
    释放资源(如停止线程、注销监听器)。

  • 代码示例

    java 复制代码
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("MyService", "Service stopped"); // 记录销毁日志
    }
(4) onBind()
  • 调用时机
    当组件通过 bindService() 绑定到服务时调用(若服务未运行,会先触发 onCreate())[citation:3][citation:11]。

  • 用途
    返回 IBinder 接口供客户端与服务交互(如跨进程通信)。

  • 代码示例

    java 复制代码
    @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() 中启动无限循环线程需谨慎:

      java 复制代码
      new Thread(() -> {
          while (true) { /* ... */ } // 需在 onDestroy() 中终止线程,否则内存泄漏!
      }).start();
  3. 服务重启策略

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

  • onCreate() :服务首次创建时初始化资源(一次性)。
  • onStartCommand() :每次 startService() 调用时执行任务。
  • onDestroy():服务销毁时释放资源。
  • onBind() :仅响应 bindService() 绑定请求(未使用可返回 null)。
相关推荐
阿巴斯甜13 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker13 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952714 小时前
Andorid Google 登录接入文档
android
黄林晴16 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android