当前位置: 首页 > 知识库问答 >
问题:

Android AlarmManager在应用程序被杀死时不会触发

宣高朗
2023-03-14

我有一个要求,执行一个任务,在正好每5分钟。我考虑了多个选项,并尝试使用AlarmManager类来触发任务来实现这一点。但是,当应用程序被杀死时,我无法触发警报。

当应用程序打开或在后台运行时,警报似乎工作得完美无缺,但一旦我退出应用程序,它似乎完全停止了。

我的实现是使用setExactandAllowWhileIdle()函数,并自己处理重复这个过程。最初的警报在5秒后触发,然后在此之后每5分钟触发一次。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_landing)
    initAlarm()
}

private fun initAlarm() {
    val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager

    val intent = Intent(this, AlarmReceiver::class.java).apply { action = "MY_ALARM" }
    val sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)

    val ALARM_DELAY_IN_SECOND = 5
    val alarmTimeAtUTC = System.currentTimeMillis() + ALARM_DELAY_IN_SECOND * 1_000

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Log.(TAG, "initAlarm() 23+ - $alarmTimeAtUTC")
        alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
    } else {
        alarm.setExact(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
    }
}
class AlarmReceiver : BroadcastReceiver() {

    companion object {
        private val TAG = AlarmReceiver::class.java.simpleName
    }

    override fun onReceive(context: Context?, intent: Intent?) {
        Log.d(TAG, "onReceive()")
        if (intent?.action == "MY_ALARM") {
            Log.d(TAG, "onReceive() - starting service")
            context?.startService(Intent(context, MyService::class.java))
            initAlarm(context)
        }
    }

    private fun initAlarm(context: Context?) {
        val alarm = context?.applicationContext?.getSystemService(Context.ALARM_SERVICE) as AlarmManager

        val intent = Intent(context, AlarmReceiver::class.java).apply { action = "MY_ALARM" }
        val sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)

        val ALARM_DELAY_IN_SECOND = 600
        val alarmTimeAtUTC = System.currentTimeMillis() + ALARM_DELAY_IN_SECOND * 1_000

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Log.d(TAG, "initAlarm() 23+ - $alarmTimeAtUTC")
            alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
        } else {
            alarm.setExact(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
        }
    }
}

MyService.kt:

override fun onCreate() {
    super.onCreate()
    Log.d(TAG, "onCreate()")
    doMyTask()
}

private fun doMyTask() {
    job = CoroutineScope(Dispatchers.IO).launch {
            // Perform task here and once complete stop service
            stopSelf()
        }
    }
}

override fun onDestroy() {
    super.onDestroy()
    Log.d(TAG, "onDestroy()")
    job?.cancel()
    job = null
}

共有1个答案

鄢选
2023-03-14

问题是,当应用程序在后台时,代码正在调用startservice()

这在Android 8之前是允许的,但现在受到以下限制:

当一个应用程序处于前台时,它可以自由地创建和运行前台和后台服务。当一个应用程序进入后台时,它有一个几分钟的窗口,在这个窗口中,它仍然可以创建和使用服务。在那个窗口的末尾,应用程序被认为是空闲的。此时,系统停止应用程序的后台服务,就像应用程序调用了服务的service.stopself()方法一样。

还值得考虑的是,是否可以通过WorkManagerFirebase Cloud Messaging完成任务。

最后,您可能需要通知您的客户,在现代Android设备上,“每5分钟”运行一次任务是不可能的。我最近没有看过Doze实现,但过去在使用SetExactandAllowWhileIdle时,在维护窗口中观察到了10分钟以上的常规延迟。但在某些情况下,延误可能会更长。

关于在BroadcastReceiver中没有调用onReceive:

 类似资料:
  • 我的目标是每12小时更新一次我的应用令牌(使用网络请求),无论应用程序是在后台还是被杀死,所以我使用workmanager来解决这个问题。但周期性任务仅在应用程序处于后台或打开状态时有效,但当我杀死应用程序时,周期性任务停止以更新我的应用程序令牌。 这是我的代码: 我正在使用workmanager 2.4.0版本

  • 我在写一个玩家轮流参加的游戏。在一个回合结束时,我将我的数据发送到服务器,并更新我的数据库,让我知道现在轮到另一个玩家了。问题是,如果有人在中途扼杀了应用程序怎么办?我是说去找任务经理然后杀了它。 编辑:我还应该提到这是在一个片段中,我正在检查这个,但不要认为这会有什么不同。

  • 问题内容: 我正在用C / C ++ 创建子进程。 当父进程结束(或由于某种原因被杀死)时,我也希望所有子进程也被杀死。 这是系统自动完成的吗?还是我必须自己做? 谢谢。 问题答案: 否。如果父进程被杀死,则子进程将成为init进程的子进程(该进程的进程ID为1,并由内核作为第一个用户进程启动)。 初始化过程会定期检查新的子代,然后等待它们(从而释放由其返回值分配的资源)。

  • 在我的应用程序中,我有一个在后台(和前台)运行。 在这个中,有一个,当它完成时,我想在某个中启动应用程序并在中自动执行一些操作,即使我的应用程序被杀死或关闭,我也希望它能正常工作。 我看到了一些答案,这是其中之一,但它对我不起作用。我找到了一个更好的解决方案,并将其作为答案发布在下面,但仍然只有在应用程序关闭但未完全关闭时才有效。 如何从后台启动,即使应用程序已关闭或关闭?