在所有最新的Android限制之后,如何设置要在确切时间安排的警报? [英] How to set an alarm to be scheduled at an exact time after all the newest restrictions on Android?

查看:77
本文介绍了在所有最新的Android限制之后,如何设置要在确切时间安排的警报?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我尝试了在StackOverflow上写过的各种解决方案(示例 此处 )。请不要在没有检查您发现的解决方案是否使用我下面编写的测试的情况下关闭它。

Note: I tried various solutions that are written about here on StackOverflow (example here). Please do not close this without checking if your solution from what you've found works using the test I've written below.

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

There is a requirement on the app, that the user sets a reminder to be scheduled at a specific time, so when the app gets triggered on this time, it does something tiny in the background (just some DB query operation), and shows a simple notification, to tell about the reminder.

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

In the past, I used a simple code to set something to be scheduled at a relatively specific time:

            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的模拟器上测试了此代码,它似乎没有触发,或者自从我提供它以来经过了很长时间才触发。我非常了解 可怕的行为 ,即 一些OEM 添加了从最近任务中删除应用程序的功能,但这是模拟器和Pixel 4上都可以使用的功能设备(股票)。

The problem

I've now tested this code on emulators on new Android versions and on Pixel 4 with Android 10, and it doesn't seem to trigger, or maybe it triggers after a very long time since what I provide it. I'm well aware of the terrible behavior that some OEMs added to removing apps from the recent tasks, but this one is on both emulators and Pixel 4 device (stock).

我在有关设置闹钟的文档,它受到应用程序的限制,因此它不会经常出现,但这并不能解释如何在特定时间设置闹钟,并且没有说明 Google的时钟的来历app 成功做到了。

I've read on the docs about setting an alarm, that it got restricted for apps so that it won't occur too often, but this doesn't explain how to set an alarm at a specific time, and it doesn't explain how come Google's Clock app succeeds doing it.

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

Not only that, but according to what I understand, it says the restrictions should be applied especially for low power state of the device, but in my case, I didn't have this state, on both the device and on the emulators. I've set the alarms to be triggered in about a minute from now.

看到很多闹钟应用不再像以前那样工作了,我认为是文档中缺少的东西。此类应用的示例是流行的及时已被Google购买的应用程序> ,但从未获得过新的更新来处理新的限制,现在用户希望返回。。但是,某些流行的应用程序确实可以正常运行,例如这一个

Seeing that many alarm clock apps don't work anymore as they used to, I think there is something that is missing on the docs. Example of such apps is the popular Timely app that was bought by Google but never got new updates to handle the new restrictions, and now users want it back.. However, some popular apps do work fine, such as this one.

要测试警报是否确实有效,我执行以下操作在首次安装该应用程序后的一分钟内,即从设备连接到PC以来(查看日志),测试从现在开始的一分钟后是否触发警报:

To test that indeed the alarm works, I perform these tests when trying to trigger the alarm in a minute from now, after installing the app for the first time, all while the device is connected to the PC (to see the logs) :


  1. 测试应用程序是否在前台,对用户可见。 -花费了1-2分钟。

  2. 测试将应用发送到后台的时间(例如,使用主屏幕按钮)-花费了约1分钟

  3. 测试何时将应用程序的任务从最近的任务中删除。 -我等了20多分钟,却没有看到警报被触发,而是写了日志。

  4. 与#3类似,但也关闭了屏幕。可能会更糟...

  1. Test when the app is in the foreground, visible to the user. - took 1-2 minutes.
  2. Test when the app was sent to the background (using the home button, for example) - took about 1 minute
  3. Test when app's task was removed from the recent tasks. - I waited more than 20 minutes and didn't see the alarm being triggered, writing to logs.
  4. Like #3, but also turn off the screen. It would probably be worse...

我尝试使用接下来的东西,但都不起作用:

I tried to use the next things, all don't work:


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

alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,timeToTrigger,endingIntent)

AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager,AlarmManager.RTC_WAKEUP,timeToTrigger,endingIntent)

以上任意一项的组合,与:

combination of any of the above, with :

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

试图使用服务而不是BroadcastReceiver。还尝试了不同的过程。

Tried to use a service instead of BroadcastReceiver. Also tried on a different process.

试图使该应用从电池优化中被忽略(这无济于事),但由于其他应用不需要

Tried making the app be ignored from the battery optimization (didn't help), but since other apps don't need it, I shouldn't use it either.

尝试过使用以下命令:



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




  1. 尝试使用的服务将触发 onTaskRemoved ,以在那里重新安排警报,但这也无济于事(尽管服务正常)。

  1. Tried having a service that will have a trigger of onTaskRemoved , to re-schedule the alarm there, but this also didn't help (the service worked fine though).

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

As for Google's Clock app, I didn't see anything special about it except that it shows a notification before being triggered, and I also don't see it in the "not optimized" section of the battery-optimization settings screen.

看到这似乎是一个错误,我在> 此处 ,包括一个示例项目和显示问题的视频。

Seeing that this seems like a bug, I reported about this here, including a sample project and video to show the issue.

我检查了模拟器的多个版本,看来此行为始于API 27(Android 8.1-Oreo)。在文档中查看 ,我不会看到提到了AlarmManager,但是相反,它是写有关各种后台工作的。

I've checked on multiple versions of the emulator, and it seems that this behavior started from API 27 (Android 8.1 - Oreo). Looking at the docs, I don't see AlarmManager being mentioned, but instead, it was written about various background work.


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

  1. How do we set something to be triggered at a relatively exact time nowadays?

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

How come the above solutions don't work anymore? Am I missing anything? Permission? Maybe I'm supposed to use a Worker instead? But then wouldn't it mean that it might not trigger on time at all?

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

How does Google "Clock" app overcome all of this, and triggers anyway on the exact time, always, even if it was triggered just a minute ago? Is it only because it's a system app? What if it gets installed as a user app, on a device that doesn't have it built-in?

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

If you say that it's because it's a system app, I've found another app that can trigger an alarm twice in 2 minutes, here, though I think it might use a foreground service sometimes.

编辑:做了个小Github存储库,请尝试在 此处

made a tiny Github repository to try ideas on, here.

编辑:最后 找到了一个示例 ,该示例既是开源的,也没有此问题。遗憾的是,它非常复杂,我仍然试图找出是什么使它如此不同(以及我应该添加到我的POC中的最小代码是什么),以使其在从最近任务中删除该应用程序后使警报保持预定状态

finally found a sample that is both open-sourced and doesn't have this issue. Sadly it's very complex and I still try to figure out what makes it so different (and what's the minimal code that I should add to my POC) that lets its alarms stay scheduled after removing the app from the recent tasks

推荐答案

找到了一种怪异的解决方法(示例 此处 )似乎适用于所有版本,甚至包括Android R:

Found a weird workaround (sample here) that seems to work for all versions, including even Android R:


  1. 在清单中声明了SAW许可:



      <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

在Android R上,您还必须将其授予。在以前,似乎不需要授予它,只是声明它。不知道为什么在R上发生了这种变化,但是我可以说,可能需要SAW作为在后台启动事物的可能解决方案,如在Android 10上此处

On Android R you will have to also have it granted. On before, doesn't seem like it's needed to be granted, just declared. Not sure why this changed on R, but I can say that SAW could be required as a possible solution to start things in the background, as written here for Android 10.


  1. 具有一项服务,该服务将检测何时删除任务以及何时删除任务,打开一个伪造的Activity,它所做的只是关闭自身:



class OnTaskRemovedDetectorService : Service() {
    override fun onBind(intent: Intent?) = null

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int) = START_STICKY

    override fun onTaskRemoved(rootIntent: Intent?) {
        super.onTaskRemoved(rootIntent)
        Log.e("AppLog", "onTaskRemoved")
        applicationContext.startActivity(Intent(this, FakeActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
        stopSelf()
    }

}

FakeActivity.kt

class FakeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("AppLog", "FakeActivity")
        finish()
    }
}

使用此主题,您还可以使用户几乎看不见该活动:

You can also make this Activity almost invisible to the user using this theme:

    <style name="AppTheme.Translucent" parent="@style/Theme.AppCompat.NoActionBar">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>

不幸的是,这是一个怪异的解决方法。我希望找到一个更好的解决方法。

Sadly, this is a weird workaround. I hope to find a nicer workaround to this.

该限制涉及启动Activity,所以我目前的想法是,也许如果我启动一个前台服务以拆分一个其次,它也有帮助,为此,我什至不需要SAW权限。

The restriction talks about starting Activity, so my current idea is that maybe if I start a foreground service for a split of a second it will also help, and for this I won't even need SAW permission.

编辑:确定,我尝试使用前台服务(示例 此处 ),但此方法无效。不知道为什么活动有效但服务无效。我什至试图重新安排在那里的警报,并试图使服务停留一会儿,即使重新安排之后也是如此。还尝试了常规服务,但是由于任务被删除,它当然立即关闭,并且根本不起作用(即使我创建了在后台运行的线程)。

OK I tried with a foreground service (sample here), and it didn't work. No idea why an Activity is working but not a service. I even tried to re-schedule the alarm there and tried to let the service stay for a bit, even after re-schedule. Also tried a normal service but of course it closed right away, as the task was removed, and it didn't work at all (even if I created a thread to run in the background).

我没有尝试过的另一种可能的解决方案是永远拥有前台服务,或者至少直到删除任务为止,但这有点奇怪,我看不到我提到的应用程序

Another possible solution that I didn't try is to have a foreground service forever, or at least till the task is removed, but this is a bit weird and I don't see the apps I've mentioned using it.

编辑:尝试在删除应用程序的任务之前(以及之后)运行前台服务,并且警报仍然有效。还尝试使该服务成为负责删除任务的事件的服务,并在发生该事件时立即将其自身关闭,并且仍然有效(示例 此处 )。这种解决方法的优点是您完全不需要SAW许可。缺点是当用户已经可以看到该应用程序时,您将获得带有通知的服务。我想知道是否可以通过活动在应用程序已经处于前台时隐藏通知。

tried to have a foreground service running before removal of the app's task, and for a bit afterwards, and the alarm still worked. Also tried to have this service to be the one in charge of task-removed event, and to close itself right away when it occurs, and it still worked (sample here). The advantage of this workaround is that you don't have to have the SAW permission at all. The disadvantage is that you have a service with a notification while the app is already visible to the user. I wonder if it's possible to hide the notification while the app is already in the foreground via the Activity.

编辑:似乎这是Android Studio上的错误(在此处报告,包括比较版本的视频)。
当您从我尝试的有问题的版本启动应用程序时,可能会导致警报被清除。

Seems it's a bug on Android Studio (reported here, including videos comparing versions). When you launch the app from the problematic version I tried, it could cause the alarms to be cleared.

如果从启动器启动应用程序,它将

If you launch the app from the launcher, it works fine.

这是设置警报的当前代码:

This is the current code to set the alarm:

        val timeToTrigger = System.currentTimeMillis() + 10 * 1000
        val pendingShowList = PendingIntent.getActivity(this, 1, Intent(this, SomeActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
        val pendingIntent = PendingIntent.getBroadcast(this, 1, Intent(this, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
        manager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingShowList), pendingIntent)

我什至不必使用 pendingShowList。也可以使用null。

I don't even have to use "pendingShowList". Using null is also ok.

这篇关于在所有最新的Android限制之后,如何设置要在确切时间安排的警报?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆