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

Android中如何实现应用被杀死后仍持续运行的进程?

解决方案:让计算任务在应用被划掉后继续完成

一、优先用前台Service保活+进度持久化

你之前用的START_STICKY Service会重启但从头执行,核心问题是没做进度保存,而且普通Service优先级低容易被厂商系统杀死。改成前台Service能大幅提升存活概率,同时配合进度持久化,即使极端情况重启也能从断点继续:

  1. 前台Service实现:
    Android 8.0+必须创建通知渠道,启动Service后立刻调用startForeground()绑定通知,让系统认为这是用户可见的任务:

    class CalculationService : Service() {
        private val CHANNEL_ID = "calculation_channel"
        private var currentProgress = 0
    
        override fun onCreate() {
            super.onCreate()
            // 读取之前保存的进度(比如从SharedPreferences)
            currentProgress = getSharedPreferences("calc_progress", MODE_PRIVATE).getInt("progress", 0)
            // 创建通知渠道(Android 8.0+)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                val channel = NotificationChannel(CHANNEL_ID, "计算任务", NotificationManager.IMPORTANCE_LOW)
                getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
            }
            // 构建前台通知
            val notification = NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("正在计算")
                .setContentText("进度:$currentProgress%")
                .setSmallIcon(R.drawable.ic_calculation)
                .build()
            startForeground(1, notification)
        }
    
        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            // 启动计算线程
            Thread {
                for (i in currentProgress..100) {
                    // 模拟计算耗时
                    Thread.sleep(100)
                    currentProgress = i
                    // 更新通知进度
                    updateNotificationProgress(i)
                    // 实时保存进度
                    getSharedPreferences("calc_progress", MODE_PRIVATE).edit()
                        .putInt("progress", i)
                        .apply()
                }
                // 计算完成,清除进度,停止前台服务
                getSharedPreferences("calc_progress", MODE_PRIVATE).edit().clear().apply()
                stopForeground(STOP_FOREGROUND_REMOVE)
                stopSelf()
            }.start()
            // 用START_REDELIVER_INTENT,系统重启时会把最后一次的Intent传过来,配合进度保存实现断点续传
            return START_REDELIVER_INTENT
        }
    
        private fun updateNotificationProgress(progress: Int) {
            val notification = NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("正在计算")
                .setContentText("进度:$progress%")
                .setSmallIcon(R.drawable.ic_calculation)
                .setProgress(100, progress, false)
                .build()
            getSystemService(NotificationManager::class.java).notify(1, notification)
        }
    
        override fun onBind(intent: Intent?): IBinder? = null
    }
    

    这里用START_REDELIVER_INTENT替代START_STICKY,系统重启Service时会重新传递最后一次的Intent,配合本地保存的进度,就能从断点继续计算,而不是从头开始。

  2. 注意事项:前台通知的重要性别设太高(比如IMPORTANCE_LOW),避免打扰用户,同时降低被用户手动关闭的概率。

二、改进WorkManager实现:断点续传

OneTimeWorkRequest的设计就是保证任务最终执行,而非让当前进程继续,所以它一定会重新调度,但你可以通过进度持久化让它从断点开始,而不是重来:

  1. 保存计算进度:把计算的中间状态(比如已处理的数据索引、完成百分比)存在Room数据库或SharedPreferences中。
  2. Work任务中读取进度:在Worker的doWork()方法里,先读取已保存的进度,然后从该进度继续计算:
    class CalculationWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
        override fun doWork(): Result {
            val sharedPref = applicationContext.getSharedPreferences("calc_progress", MODE_PRIVATE)
            var currentProgress = sharedPref.getInt("progress", 0)
    
            for (i in currentProgress..100) {
                Thread.sleep(100)
                currentProgress = i
                // 保存进度
                sharedPref.edit().putInt("progress", i).apply()
                // 更新WorkManager进度(可选,用于UI展示)
                setProgressAsync(workDataOf("progress" to i))
            }
    
            // 计算完成,清除进度
            sharedPref.edit().clear().apply()
            return Result.success()
        }
    }
    
  3. 提升Work任务优先级:Android 12+可以调用setForeground()让Work任务变成前台优先级,降低被系统杀死的概率:
    val workRequest = OneTimeWorkRequestBuilder<CalculationWorker>()
        .setForegroundInfoAsync {
            val channelId = "calculation_channel"
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                val channel = NotificationChannel(channelId, "计算任务", NotificationManager.IMPORTANCE_LOW)
                applicationContext.getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
            }
            val notification = NotificationCompat.Builder(applicationContext, channelId)
                .setContentTitle("正在计算")
                .setSmallIcon(R.drawable.ic_calculation)
                .build()
            ForegroundInfo(2, notification)
        }
        .build()
    WorkManager.getInstance(applicationContext).enqueue(workRequest)
    

三、其他补充方案

  • JobIntentService:兼容Android O以下版本,它会在后台执行任务,O及以上会自动转为前台Service,但现在官方更推荐用WorkManager + 前台通知的组合。
  • 厂商白名单引导:部分国产厂商的后台管理策略严格,即使前台Service也可能被杀死,可以在应用内引导用户将应用加入系统后台白名单(比如小米的“自启动管理”、华为的“受保护应用”),但这属于用户操作层面的优化。

核心原则

不管用哪种方案,进度持久化是关键——只有把计算的中间状态保存下来,才能避免进程重启后从头开始。而提升进程优先级(前台Service/前台Work)则是降低被系统杀死概率的核心手段。

内容的提问来源于stack exchange,提问作者Spiros

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:37:11