如何在所有最新的Android限制之后设置要在确切时间安排的警报?

问题描述 投票:3回答:1

注意:我尝试了在StackOverflow上写在这里的各种解决方案(示例here)。请不要在未检查所找到的解决方案是否可以使用我在下面进行的测试的情况下关闭此功能。

背景

应用程序中有一项要求,即用户将提醒设置为在特定时间进行安排,因此,当应用程序在此时间触发时,它会在后台执行一些微小的操作(只是一些数据库查询操作),并且显示一个简单的通知,以告知提醒。

过去,我使用简单的代码来设置要在相对特定的时间安排的内容:

            val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
            val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
            when {
                VERSION.SDK_INT >= VERSION_CODES.KITKAT -> alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
                else -> alarmManager.set(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
            }
class AlarmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d("AppLog", "AlarmReceiver onReceive")
        //do something in the real app
    }
}

用法:

            val timeToTrigger = System.currentTimeMillis() + java.util.concurrent.TimeUnit.MINUTES.toMillis(1)
            setAlarm(this, timeToTrigger, 1)

问题

我现在已经在新的Android版本和带有Android 10的Pixel 4的模拟器上测试了此代码,它似乎没有触发,或者自从我提供它以来经过了很长时间才触发。

我已经读过the docs关于设置警报的信息,该警报受到应用程序的限制,因此不会经常发生,但这并不能解释如何在特定时间设置警报,并且无法解释Google's Clock app如何成功做到这一点。

不仅如此,而且据我所知,它说限制应特别适用于设备的低功耗状态,但就我而言,我在设备和仿真器上都没有此状态。我将警报设置为从现在开始大约一分钟后触发。

我尝试过的

[为了测试警报的确有效,在首次安装该应用程序后的一分钟之后,我尝试在从现在开始的一分钟内触发警报,这些测试都是在设备连接到PC的整个过程中进行的(以查看日志) :

  1. 测试应用在前景中的位置,对用户可见。 -花费了1-2分钟。
  2. [将应用程序发送到后台的时间(例如,使用主屏幕按钮进行测试-大约花费了1分钟]
  3. 测试何时将应用程序的任务从最近的任务中删除。 -我等了20多分钟,却没有看到警报被触发,没有写日志。
  4. 像#3,但也要关闭屏幕。可能会更糟...

我试图使用接下来的东西,所有的东西都不起作用:

  1. alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)

  2. alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)

  3. AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)

  4. 以上任何一项的组合,与:

    if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) alarmManager.setWindow(AlarmManager.RTC_WAKEUP, 0, 60 * 1000L, pendingIntent)

  5. 尝试使用服务代替BroadcastReceiver。还尝试了其他过程。

  6. 尝试使用此:

            if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
                alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
            AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)

关于Google的Clock应用程序,除了在触发之前会显示通知,我没有看到其他特别之处,并且在电池优化设置屏幕的“未优化”部分中也未看到它。

问题

  1. 如今我们如何设置要在相对准确的时间触发的内容?

  2. 以上解决方案为何不再起作用?我有什么想念的吗?允许?也许我应该改为使用工人?但是那不是意味着它可能根本不会按时触发吗?

  3. Google“时钟”应用程序如何克服所有这些问题,并且无论如何都会在准确的时间始终触发,即使它是在一分钟前触发的?仅仅是因为它是一个系统应用程序吗?如果将它作为用户应用程序安装在没有内置设备的设备上怎么办?

[如果您说这是因为它是一个系统应用程序,我发现另一个应用程序可以在2分钟内两次触发警报,here,尽管我认为它有时可能会使用前台服务。

android alarmmanager
1个回答
0
投票
  1. 确保您广播的意图是明确的并且具有Intent.FLAG_RECEIVER_FOREGROUND标志。

https://developer.android.com/about/versions/oreo/background#broadcasts

Intent intent = new Intent(context, Receiver.class);
intent.setAction(action);
...
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

PendingIntent operation = PendingIntent.getBroadcast(context, 0, intent, flags);
  1. 定位API 23+时使用setExactAndAllowWhileIdle()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, operation);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    alarmManager.setExact(AlarmManager.RTC_WAKEUP, time, operation);
} else {
    alarmManager.set(AlarmManager.RTC_WAKEUP, time, operation);
}
  1. 作为前台服务启动警报:

https://developer.android.com/about/versions/oreo/background#migration

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(intent);
} else {
    context.startService(intent);
}
  1. 并且不要忘记权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
热门问题
推荐问题
最新问题