如何检查AlarmManager是否已经设置了警报?


231

当我的应用程序启动时,我希望它检查是否已设置并正在运行特定警报(通过AlarmManager注册)。谷歌的结果似乎表明,没有办法做到这一点。这还正确吗?我需要进行此检查,以便在采取任何措施来创建新警报之前为用户提供建议。


4
请验证解决您问题的答案或发布您自己的解决方案。
阿尼斯(Anis)

Answers:


322

跟进发表的评论,这里是详细的解决方案。假设您注册了一个具有未决意图的重复警报,如下所示:

Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, 
                                      intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 1);

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60, pendingIntent);

您将检查其是否处于活动状态的方法是:

boolean alarmUp = (PendingIntent.getBroadcast(context, 0, 
        new Intent("com.my.package.MY_UNIQUE_ACTION"), 
        PendingIntent.FLAG_NO_CREATE) != null);

if (alarmUp)
{
    Log.d("myTag", "Alarm is already active");
}

此处的关键是FLAG_NO_CREATE如javadoc中所描述的:(if the described PendingIntent **does not** already exists, then simply return null而不是创建一个新的)


9
是否必须仅将Intent与Action String一起使用?我尝试指定一个类,新的Intent(context,MyClass.class),但它似乎不起作用。即使警报正在运行,它也始终返回null。
toc777

5
toc777,否,它必须是一个字符串,该字符串与manifest.xml中的意图过滤器中声明的动作相匹配
Chris Knight

4
克里斯,这是引起我问题的另一个问题。我上面提到的意图确实有效:)
toc777

41
请注意,您需要同时调用alarmManager.cancel(pendingIntent)pendingIntent.cancel(),此解决方案才能返回false。
凯文·库珀

26
如果情况不是很明显,则此答案中的代码不会验证挂起的意图是否已在警报管理器中注册。该代码只是简单地验证PendingIntent是通过具有等效目标intent的getBroadcast创建的。您可以通过在全部getBroadcast之后但在所有日历和警报管理器之前运行alarmUp代码来证明这一点。它将返回true。这个事实说明了为什么必须PendingIntent.cancel才能使该值返回false。严格来说,这不能回答问题。
bigh_29 2015年

114

对于其他可能需要这样做的人,这是一个答案。

adb shell dumpsys alarm

您可以知道已设置警报以及它们何时警报和间隔。此警报已被调用多少次。


36
这并不是OP的程序化答案,而是一个不错的提示。很高兴知道。
JustSomeGuy 2015年

2
附加grep来过滤通常很长的警报列表:adb shell dumpsys alarm | grep <e.g. package name of your app>也可以在新的Windows系统上使用(我使用Win10)
muetzenflo

3
grep是在移动设备而不是PC上执行的。因此,grep是否有效取决于Android操作系统。较旧的手机不附带grep。
亨宁

53

与接收者一起工作的例子(最重要的答案就是采取行动)。

//starting
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), MyReceiver.class);
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//my custom string action name
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//used unique ID as 1001
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), aroundInterval, pendingIntent);//first start will start asap

//and stopping
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//the same as up
alarmManager.cancel(pendingIntent);//important
pendingIntent.cancel();//important

//checking if alarm is working with pendingIntent
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
boolean isWorking = (PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_NO_CREATE) != null);//just changed the flag
Log.d(TAG, "alarm is " + (isWorking ? "" : "not") + " working...");

值得一提:

如果创建的应用程序稍后(流程)重新检索相同类型的PendingIntent(相同的操作,相同的Intent的-动作,数据,类别,组件,标志),它将收到一个PendingIntent,表示相同的令牌(如果该令牌仍然有效),并且因此可以调用cancel()将其删除。

简而言之,您的PendingIntent应该具有相同的功能(操作和意图的结构)以对其进行控制。


1
我不确定这是否足够。如果在AlarmManager中注册了PendingIntent,然后通过两种取消方法将其停止,则上面的'isWorking'仍然为true。PendingIntent似乎尚未从AlarmManager中删除,并且将继续返回实例。那么我们如何有效地知道何时打开/关闭警报?
johnDisplayClass

这实际上工作得很好。注意事项:setAction()和requestCode()在所有getBroadcast()中必须相同,值得从设备上卸载应用程序。那让我失望了。谢谢
johnDisplayClass '16

效果很好。谢谢!
Ambran'9

1
很好的例子,但我不会在那里使用1001作为私有请求代码。仅需0以使示例更加明显。
克里斯(Chris

1
请不要使用“最佳答案”等。而是提供指向答案的链接。因为答案可以根据受欢迎程度来更改页面上的位置。
卡希尔(Kathir)'18

44

请注意文档中有关“警报管理器”的set方法的引用

如果已为此计划调度了一个警报(两个意图的相等性由Intent.filterEquals定义),则将其删除并替换为该警报。

如果知道要设置警报,则无需费心检查警报是否已存在。每次您的应用启动时就创建它。您将用相同的替换过去的任何警报Intent

如果要尝试计算以前创建的警报还有多少时间,或者是否真的需要知道这种警报是否存在,则需要使用其他方法。要回答这些问题,请在创建警报时考虑保存共享的偏好数据。您可以存储设置闹钟时的时钟时间戳,希望闹钟响起的时间以及重复周期(如果设置了重复闹钟)。


2
我认为这应该是公认的答案。除非OP出现特殊情况以证明无需重发警报
否则

就我而言,我想知道警报是否已设置,如果希望,我不想创建新警报或重置现有警报。
Imran Aslam

2
极好的答案。OP为何根本不检查这一点?您什么都不需要做。
维杰·库马尔·坎塔

2
此解决方案中有很多漏洞,它可能会覆盖先前创建的警报时间(假设是否需要像t + 24这样指定时间),因此每次启动应用程序时,警报时间都会继续前进,直到永远无法获取触发很多,因此检查警报是否已经存在是一种更可靠的方法
Naga

10

我有2个警报。我将Intent与Extras结合使用,而不是采取行动来识别事件:

Intent i = new Intent(context, AppReciever.class);
i.putExtra("timer", "timer1");

事实是,使用diff extras的意图(和警报)将不会唯一。因此,要确定哪个警报处于活动状态,我必须定义diff requestCode-s:

boolean alarmUp = (PendingIntent.getBroadcast(context, MyApp.TIMER_1, i, 
                    PendingIntent.FLAG_NO_CREATE) != null);

这是警报的创建方式:

public static final int TIMER_1 = 1;
public static final int TIMER_2 = 2;

PendingIntent pending = PendingIntent.getBroadcast(context, TIMER_1, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);
pending = PendingIntent.getBroadcast(context, TIMER_2, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);

使用额外的意图,这个解决方案对我有用。我使用的服务只是一个更改,所以我将其更改为PendingIntent.getService
Pankaj

8

刚找到另一种解决方案,它似乎对我有用

Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);

boolean isWorking = (PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, PendingIntent.FLAG_NO_CREATE) != null);
if (isWorking) {Log.d("alarm", "is working");} else {Log.d("alarm", "is not working");}

if(!isWorking) {
    pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent,    PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    int timeNotif = 5 * 60 * 1000;//time in ms, 7*24*60*60*1000 for 1 week
    Log.d("Notif", "Notification every (ms): " + timeNotif);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), timeNotif, pendingIntent);
    }

有时,在棉花糖上,在强制停止应用后,getBroadcast()将返回非空值,但未设置警报。
Hopia '18

6

尽管这里几乎每个人都给出了正确的答案,但是没有人解释“警报”的工作依据是什么

您实际上可以AlarmManager这里了解更多有关它的信息。但这是快速答案

AlarmManager基本上看到PendingIntent了将来某个时间的时间表。因此,要取消预定的警报,您需要取消PendingIntent

创建广告素材时,请始终注意两件事 PendingIntent

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • 请求代码-充当唯一标识符
  • 标志-定义行为 PendingIntent

现在,要检查警报是否已安排或取消警报,您只需要访问该警报即可PendingIntent。如果您使用相同的请求代码并按FLAG_NO_CREATE如下所示使用,则可以完成此操作

PendingIntent pendingIntent=PendingIntent.getBroadcast(this,REQUEST_CODE,intent,PendingIntent.FLAG_NO_CREATE);

if (pendingIntent!=null)
   alarmManager.cancel(pendingIntent);

随着FLAG_NO_CREATE它会返回null,如果PendingIntent不存在。如果已经存在,则返回对现有对象的引用PendingIntent


如果请求代码是标识符,将Intent与匹配的Action一起传递是否重要?
Sekula1991 '19

如果您有待处理的意图,是否可以通过Alarmanager获取安排警报的时间?
史密斯先生

4

我制作了一个简单的(无论是否愚蠢的)bash脚本,该脚本从adb shell中提取了long并将其转换为时间戳,并以红色显示。

echo "Please set a search filter"
read search

adb shell dumpsys alarm | grep $search | (while read i; do echo $i; _DT=$(echo $i | grep -Eo 'when\s+([0-9]{10})' | tr -d '[[:alpha:][:space:]]'); if [ $_DT ]; then echo -e "\e[31m$(date -d @$_DT)\e[0m"; fi; done;)

试试吧 ;)


1
    Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    sqlitewraper.context, 0, intent,
                    PendingIntent.FLAG_NO_CREATE);

FLAG_NO_CREATE不是创建挂起的意图,因此它将布尔值设置为false。

            boolean alarmUp = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_NO_CREATE) != null);

            if (alarmUp) {
                System.out.print("k");

            }

            AlarmManager alarmManager = (AlarmManager) sqlitewraper.context
                    .getSystemService(Context.ALARM_SERVICE);
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis(), 1000 * 60, pendingIntent);

在AlarmManager检查Pending Intent的值后,它为true,因为AlarmManager更新了Pending Intent的标志。

            boolean alarmUp1 = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_UPDATE_CURRENT) != null);
            if (alarmUp1) {
                System.out.print("k");

            }

0

我的印象是,没有办法做到这一点,但这会很好。

通过将Alarm_last_set_time记录在某处,并使用On_boot_starter BroadcastReciever:BOOT_COMPLETED可以达到类似的效果。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.