【问题标题】:Android O and background limits prevents simple alarm notificationAndroid O 和​​后台限制阻止了简单的警报通知
【发布时间】:2017-07-10 15:35:36
【问题描述】:

我自己的应用使用了与 2016 年 Google I/O 应用所展示的完全相同的技术。see source

我需要在一个非常具体的时间点提醒用户 - 使用通知。

为此,我使用AlarmManager 在正确的时间点唤醒设备:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        am.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
    } else {
        am.set(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
    }

pendingIntent 是这样创建的:

    final Intent intent = new Intent(MyAlarmService.ACTION_NOTIFY_RIDE, null, this, MyAlarmService.class);
    pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

现在,我的 MyAlarmService 类是一个简单的 IntentService 处理唤醒只是为了为用户创建通知。

我在日志中得到的消息如下:

W/ActivityManager: Background start not allowed: service Intent { act=xxx.xxx.xxx.action.NOTIFY_RIDE flg=0x4 cmp=xxx.xxx.xxx./xxx.xxx.xxx.service.MyAlarmService (has extras) } 

现在,Google 自己的实现显然已经坏了——即使我不想做任何繁重的后台工作,我也不能再使用这种技术了。但是我应该如何在一个非常特定的时间点唤醒用户呢? (把我的应用想象成一个闹钟)

【问题讨论】:

    标签: alarmmanager android-notifications wakeup android-8.0-oreo


    【解决方案1】:

    我的问题的答案很简单:

    不要使用服务来显示通知(就像 Google 在其 IO Schedule 应用中所做的那样!),而是使用 BroadcastReceiver!

    我不知道为什么 Google 确实使用了 IntentService,但现在在 Android O 上,由于后台执行限制,这根本不再工作。

    BroadcastReceiver 虽然显然仍然可以运行片刻并显示通知。

    如果有人能告诉我为什么 Google 首先要使用 IntentService,那就加分吧……我花了很长时间才弄明白,因为我认为 Google 知道他们在做什么……:(

    【讨论】:

    • 不错!在应用程序进入 ANR 之前,BroadcastReceiver 会持续多长时间?你说得简短——基本上,有多简短?谢谢!
    • 您始终可以使用 JobIntentService,它使用调度程序 API 及其后台兼容,它将覆盖打瞌睡的限制,我已在从处理主屏幕小部件及其后台服务的迁移中使用它完美运行
    • @AhmedAwad 您的建议是从BroadcastReceiver 开始JobIntentService,而不是使用JobIntentService 而不是BroadcastReceiver(同样,与之前的IntentService 一样)报警的PendingIntent,对吧?
    【解决方案2】:

    但是我应该如何在非常特定的时间点唤醒用户呢? (把我的应用想象成一个闹钟)

    首先,您的代码不准确。如果设备处于打盹模式,我预计最多 +/- 10 分钟。如果您想要准确的计时,并且您的应用确实是一个闹钟,请使用setAlarmClock()

    对于您现有的代码,use getForegroundService() 而不是 API 级别 26+ 上的 getService()

    【讨论】:

    • 这是一个闹钟。它提醒您有一辆公共汽车将在 x 分钟后出发。这就是为什么我选择了这种在时间方面完美(并且仍然有效)的展示方式。我应该在哪里使用 getForegroundService() ?
    • @Zordid:“我应该在哪里使用 getForegroundService() ?” -- 在您问题的代码中,您使用getService() 创建PendingIntent。您可以在 API 级别 26+ 上将其替换为 getForegroundService()
    • 在 Android O 中仍然允许使用 PendingIntent.getBroadcast + AlarmManager 在固定内部运行小任务的技术吗?
    • @CheokYanCheng:AlarmManager 仍然有效,但受到我们自 Android 6.0 以来一直在处理的相同打盹模式和应用程序待机限制的影响。但是,在 Android 8.0+ 上,由AlarmManager 启动的后台服务只能运行约 1 分钟,然后才会停止。
    • 当我看到一些开发人员在执行警报任务时面临问题。 stackoverflow.com/questions/45815899/…想知道是不是因为他们没有明确地启动意图?
    【解决方案3】:

    您甚至可以考虑定期运行 SyncAdapter/Job Scheduler 执行相同的业务逻辑。 并且要设置新的定期同步,您可以在应用程序启动本身上首次设置。

    【讨论】:

    • 我遇到了同样的问题,我想和你做同样的事情,但它没有奏效(可能是因为我在服务中做了一些繁重的工作)。至于谷歌最初的实现,他们使用了一项服务(我认为)来处理任何可能使系统杀死广播接收器的繁重工作。这就是为什么实施在我的情况下不起作用的原因。所以我还在寻找解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多