You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 10:21:01