Kotlin Android开发:如何实现后台服务在应用关闭后仍持续运行?
解决方案
你的普通后台服务被系统1分钟后查杀是Android系统的后台限制机制,直接改造成前台服务即可实现熄屏、应用退后台甚至划掉进程后持续运行,操作步骤如下:
1. 先添加必要权限
在AndroidManifest.xml中添加以下权限:
<!-- Android 9及以上前台服务必备权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Android 13及以上通知权限,用于展示前台服务通知 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
同时要在manifest的<application>标签内注册你的服务:
<service android:name=".TimerService" />
2. 修改TimerService代码
改造后的完整代码如下:
class TimerService : Service() { override fun onBind(p0: Intent?): IBinder? = null // 通知ID,只要是应用内唯一的正整数即可 private val NOTIFICATION_ID = 1001 // 通知渠道ID,自定义字符串即可 private val CHANNEL_ID = "timer_service_channel" private val timer = Timer() override fun onCreate() { super.onCreate() // Android 8及以上需要先创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( CHANNEL_ID, "秒表运行通知", NotificationManager.IMPORTANCE_LOW ).apply { description = "用于展示秒表运行状态" // 关闭通知声音和震动,避免打扰 setSound(null, null) enableVibration(false) } val notificationManager = getSystemService(NotificationManager::class.java) notificationManager.createNotificationChannel(channel) } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { // 构建前台服务通知 val notification = NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("秒表正在运行") .setContentText("计时中,点击可返回应用") .setSmallIcon(R.drawable.ic_timer) // 替换为你自己应用的图标资源 .setContentIntent( // 点击通知跳转到你的秒表主页面,替换为你自己的主Activity类名 PendingIntent.getActivity( this, 0, Intent(this, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) ) .build() // 启动前台服务,必须在onStartCommand调用后5秒内执行,否则会报错 startForeground(NOTIFICATION_ID, notification) val time = intent.getDoubleExtra(TIME_EXTRA, 0.0) timer.scheduleAtFixedRate(TimeTask(time), 0, 1000) // 改成START_STICKY,服务被意外杀掉后会自动重启 return START_STICKY } override fun onDestroy() { timer.cancel() // 停止前台服务并移除通知 stopForeground(STOP_FOREGROUND_REMOVE) super.onDestroy() } private inner class TimeTask(private var time: Double) : TimerTask() { override fun run() { val intent = Intent(TIMER_UPDATED) time++ intent.putExtra(TIME_EXTRA, time) sendBroadcast(intent) } } companion object { const val TIMER_UPDATED = "timerUpdated" const val TIME_EXTRA = "timeExtra" } }
3. 修改服务启动逻辑
启动服务时,Android 8及以上版本需要调用startForegroundService方法而非普通的startService:
// 启动服务的代码示例,放在你启动秒表的位置 val intent = Intent(context, TimerService::class.java) intent.putExtra(TimerService.TIME_EXTRA, currentTime) // 传入初始计时时间 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(intent) } else { context.startService(intent) }
注意事项
- 前台服务运行时必须在通知栏展示常驻通知,这是Android系统的强制要求,无法隐藏
- 首次启动时如果是Android 13及以上版本,需要先申请通知权限,否则通知无法展示,服务会被系统强行停止
- 小米、华为等国产定制ROM需要额外给应用开启「后台运行权限」「自启动权限」,否则划掉应用后服务仍可能被系统查杀
内容的提问来源于stack exchange,提问作者Casper Stockman
相关产品推荐
相关产品推荐

