如何检查AlarmManager是否已设置闹钟?

问题描述 投票:210回答:10

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

android alarmmanager
10个回答
308
投票

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

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中所述(而不是创建一个新的)


0
投票

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

您可以通过在某处记录Alarm_last_set_time并使用On_boot_starter BroadcastReciever:BOOT_COMPLETED来实现类似的结果。


109
投票

对于可能需要这个的人来说,这是一个答案。

使用adb shell dumpsys alarm

您可以知道已经设置了警报以及它们何时会发出警报和间隔。此外,还会调用此警报的次数。


48
投票

带接收器的工作示例(最重要的答案就是行动)。

//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应该具有相同的功能(操作和意图的结构)来控制它。


41
投票

请注意来自报警管理器设置方法的文档中的this quote

如果已经安排了此Intent的警报(Intent.filterEquals定义了两个意图相等),那么它将被删除并替换为此。

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

如果您正在尝试计算先前创建的警报剩余时间,或者您确实需要知道此警报是否存在,则需要采用不同的方法。要回答这些问题,请考虑在创建警报时保存共享的pref数据。您可以在设置闹钟时存储时钟时间戳,预计闹钟关闭的时间以及重复周期(如果设置重复闹钟)。


10
投票

我有2个闹钟。我使用intent而不是action来识别事件:

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);

7
投票

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

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);
    }

3
投票

我制作了一个简单的(愚蠢的或非愚蠢的)bash脚本,它从adb shell中提取长片,将它们转换为时间戳并以红色显示。

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;)

试试吧 ;)


3
投票

虽然这里几乎每个人都给出了正确的答案,但没有任何机构解释警报的工作原理

你可以真正了解更多关于AlarmManager及其工作的here。但这是快速回答

你看,AlarmManager基本上会在将来的某个时间安排一个PendingIntent。因此,要取消预定的闹钟,您需要取消PendingIntent

在创建PendingIntent时始终记下两件事

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • 请求代码 - 作为唯一标识符
  • Flag - 定义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的引用


1
投票
PendingIntent

FLAG_NO_CREATE不会创建待定意图,因此它给出布尔值false。

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

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

            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);
© www.soinside.com 2019 - 2024. All rights reserved.