我编写了一个前台服务,对于低于Oreo版本的所有操作系统都可以正常工作。从Oreo开始,在关闭并从最近使用应用程序中删除应用程序5分钟后,应用程序进程会被杀死。
根据Android开发者文档中有关后台执行限制的规定,操作系统不应杀死正在运行前台服务并在通知窗口中显示通知的应用程序。
按照开发者文档上的指南,我遵循以下步骤启动前台服务:
- 使用
startForegroundService()
方法启动前台服务。 - 在启动服务后的5秒内,使用
startForeground()
显示服务通知。 - 从
service
的onStartCommand()
方法返回START_STICKY
。
我在以下手机上遇到了这个问题:
- OnePlus 5T
- Vivo
- Oppo
- Mi
我尝试了什么来防止前台服务被销毁?
- 通过向用户显示系统对话框来禁用应用程序的电池优化以禁用深度睡眠模式。
我尝试了什么来重新启动前台服务?
- 使用
AlarmManager
从onTaskRemoved()
方法重新启动服务。请参见此链接获取详细信息。
据我了解,这些制造商已经定制了AOSP,并且没有遵守允许运行前台服务的操作系统规定。也许这些制造商之所以这样做是为了让用户获得更长的电池使用时间。
前台服务类
class DataCaptureService : Service() {
private var isServiceStarted = false
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakelockTag123").apply {
acquire()
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val serviceAction = intent?.action
LogUtils.logD("OnStartCommand(). Action=$serviceAction")
if (Constants.INTENT.ACTION_STOP_SERVICE == serviceAction) {
LogUtils.logD("Stopping data capture service")
stopForeground(true)
stopSelf()
} else if (Constants.INTENT.ACTION_START_SERVICE == serviceAction && !isServiceStarted) {
LogUtils.logD("Starting data capture service")
isServiceStarted = true
// Here showing notification using a utility method (startForeground(id, notification))
createNotification(this)
// Doing some stuff here
----------------------
//
}
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
if (isServiceStarted) {
LogUtils.logD("onDestroy of DataCaptureService method is invoked")
// Doing some stuff here
----------------------
//
isServiceStarted = false
if (wakeLock.isHeld) {
wakeLock.release()
}
}
}
override fun onTaskRemoved(rootIntent: Intent?) {
LogUtils.logD("onTaskRemoved of DataCaptureService method is invoked")
ensureServiceStaysRunning()
super.onTaskRemoved(rootIntent)
}
private fun ensureServiceStaysRunning() {
val restartAlarmInterval = 60 * 1000
val resetAlarmTimer = 30 * 1000L
// From this broadcast I am restarting the service
val restartIntent = Intent(this, ServiceRestartBroadcast::class.java)
restartIntent.action = "RestartedViaAlarm"
restartIntent.flags = Intent.FLAG_RECEIVER_FOREGROUND
val alarmMgr = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val restartServiceHandler = @SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message) {
val pendingIntent = PendingIntent.getBroadcast(applicationContext, 87, restartIntent, PendingIntent.FLAG_CANCEL_CURRENT)
val timer = System.currentTimeMillis() + restartAlarmInterval
val sdkInt = Build.VERSION.SDK_INT
if (sdkInt < Build.VERSION_CODES.KITKAT)
alarmMgr.set(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
else if (Build.VERSION_CODES.KITKAT <= sdkInt && sdkInt < Build.VERSION_CODES.M)
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
else if (sdkInt >= Build.VERSION_CODES.M) {
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
}
sendEmptyMessageDelayed(0, resetAlarmTimer)
stopSelf()
}
}
restartServiceHandler.sendEmptyMessageDelayed(0, 0)
}
}
请分享您的建议,如果您遇到类似问题并成功找到解决方案。