【问题标题】:PendingIntent with IntentService not working带有 IntentService 的 PendingIntent 不起作用
【发布时间】:2018-05-03 09:20:56
【问题描述】:

以下代码非常适合Activity

Intent intent = new Intent(context, MyActivity.class);
PendingIntent operation = PendingIntent.getActivity(context, 
                              0, 
                              intent, 
                              PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP, 
                              startTime.getTimeInMillis(),
                              operation);

但是,当我为IntentService 做同样的事情时,它只有在startTime 和我设置闹钟的时间在同一天时才有效。例如如果我今天将闹钟设置为下午 5 点,它将被执行,但是当我今天将闹钟设置为明天下午 5 点时,它将不会执行。如果这是Activity,那么它适用于两种情况。

Intent intent = new Intent(context, MyService.class);
PendingIntent operation = PendingIntent.getService(context, 
                              0, 
                              intent, 
                              PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP, 
                              startTime.getTimeInMillis(),
                              operation);

如何解决这个问题?

我想要实现的目标是每天在准确的时间执行IntentService

【问题讨论】:

  • 你的目标SDK是什么?你在什么设备上测试?当闹钟应该响起时设备是否已唤醒?
  • TargetSDK 为 27。在 API 27 官方模拟器上测试。是的,设备处于唤醒状态。
  • 您可以尝试将目标 SDK 设置为 25 并查看其行为是否有所不同吗?
  • 您也可以尝试使用 setExactAndAllowWhileIdle() 而不是 setExact() 来查看这是否会改变 SDK 27 上的行为。

标签: android alarmmanager android-pendingintent intentservice android-alarms


【解决方案1】:

我想要实现的目标是每天在准确的时间执行 IntentService。

Google 在不同版本之间逐渐加大了这方面的难度。见Android AlarmManager setExact() is not exact。对于您的情况,可能有两种方法可以解决此问题:

  1. 您启动了一个 Activity,它启动了服务(因为启动 Activity 似乎对您有用)
  2. 您使用setExactAnd...setAlarmClocksetAlarmClock 也会在新的“打瞌睡”模式下触发,请参阅 https://stackoverflow.com/a/47049705/1587329

另一种方法是重新考虑为什么以及您是否真的需要它......或者如果 JobScheduler 不能更容易地满足您的目的。

【讨论】:

    【解决方案2】:

    添加用此行替换您的行:

    alarmmanager.setRepeating(AlarmManager.RTC_WAKEUP, 
                              startTime.getTimeInMillis(),
                              operation);
    

    它将按照您在警报管理器中设置的特定间隔重复

    【讨论】:

    • 从 API 19 开始,所有重复警报都是不准确的。 developer.android.com/reference/android/app/…
    • 是的,我知道。那么您应该更改设置警报的流程。当第一次闹铃响起时,得到当前时间后再次设置闹铃。通过将相同的请求代码放入 alarmmanager.setExact(AlarmManager.RTC_WAKEUP, startTime.getTimeInMillis(), operation);
    • 我也做了同样的事情,但是只有当 PendingIntent 是 Activity 时它才能正常工作。它不适用于 IntentService。
    • 然后尝试使用 BroadcastReceiver 而不是 intentService。因为我用 BroadcastReceiver 为我的项目做了同样的事情。及其工作正常@AksharPatel
    【解决方案3】:

    将 AlarmManager 替换为以下代码:

    alarmManager.setRepeating(AlarmManager.RTC, 
                              timeMills, 
                              AlarmManager.INTERVAL_DAY, 
                              pendingIntent);
    

    为我工作。

    【讨论】:

    【解决方案4】:

    这是底部的详细答案检查链接以获取更多详细信息。 希望这会有所帮助。您的问题也可能与 android 版本有关,因此请查看链接了解更多详情

    app 获取 AlarmManager 的实例并使用 PendingIntent 设置警报。有关使用和设置警报的更多信息将在下一节中介绍。 AlarmManager 是支持 AlarmManagerService 的应用程序端接口。它抽象了Binder接口的细节,用于与承载AlarmManagerService的系统进程(system_server)进行通信。这两个组件管理应用程序设置的警报并将正确发送 PendingIntent。此管理器/服务架构在整个 Android 框架中使用,并用于安全和隔离目的。 system_server 进程以普通应用程序没有的权限运行。如果您不熟悉 Android 对权限的使用,请参阅本文了解有关应用进程和用户 ID 的更多详细信息。这些额外的权限允许 system_server 访问底层内核警报驱动程序。警报驱动程序负责管理设置警报以唤醒设备,而不管 SoC 的睡眠状态如何。

    当警报被触发时,设备会被唤醒(如果睡着了),AlarmManagerService 会收到警报到期的通知。然后它将相应地发送 PendingIntent。这将导致 MyApp 中的相应组件被激活。如果 MyApp 没有启动或者它的进程没有被缓存,它会被启动以便激活组件。

    基本用法如下

    public class MyActivity extends Activity {
    ...
    private AlarmManager  mAlarmMgr;
    ...
    public void onCreate(Bundle savedInstance) {
        ...
        mAlarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        ...
    }
    ...
    
    
    }
    

    让我们使用组件名称为我们的 MyActivity 创建一个 PendingIntent

    Intent alarmIntent = new Intent(context, MyActivity.class);
    PendingIntent pend = PendingIntent.getActivity(context,
                                  0,
                                  alarmIntent,
                                  PendingIntent.FLAG_UPDATE_CURRENT);
    

    现在我们有了 PendingIntent 和 AlarmManager,我们可以设置警报,以便在警报到期时触发 Activity。为此,我们需要弄清楚我们希望闹钟何时响起,以及它是应该唤醒设备还是在下次唤醒设备时才发出。请记住,我们有两种不同的方式来指定闹钟时间:经过时间或日历 (RTC) 时间。所以我们的选项是 ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC 或 RTC_WAKEUP。 _WAKEUP 变体是我们的“攻击性”警报,我们希望设备在低电量状态下调用我们的应用程序。对于我们的示例应用,让我们在自定义 BroadcastReceiver 中进行设置,并让它在设备启动后大约 30 秒触发我们的 Activity

    public class MyBootReceiver extends BroadcastReceiver {
    public void onReceive(Context, context, Intent intent) {
        ...
        AlarmManager alarmMgr =
            (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        long wakeTime = SystemClock.elapsedRealtime() + 30000;
        alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeTime, pend);
    }
    }
    

    现在,当我们的设备启动并发送 BOOT_COMPLETED 广播时,我们的应用进程将启动,我们的接收器将设置警报以触发我们的 Activity 大约 30 秒后启动。请注意,在 Android 3.1 或更高版本的设备上,您必须在 BOOT_COMPLETED 之前先手动启动您的应用。

    信用归作者BLOG

    如果您想使用 SetExact 设置重复警报,您必须同时停止所有其他待处理的意图,请检查此link,因为这里有很多如何做到这一点的示例!再次感谢这位作家

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多