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


当前回答

如果你的目标是Android 12(即目标SDK 31),那么,对于AlarmManager, PendingIntent不能在没有Mutable或Immutable标志的情况下创建。如果没有这个可变性标志,应用程序将抛出一个运行时错误。有关这方面的更多详细信息,请参阅本文档。下面的代码片段对我来说是有用的,它将帮助那些将应用程序定位于Android 12的人。

创建告警:

public static void setupReminderServiceAlarm ( Context context ) {
    Log.d ( TAG, "Trying to setup reminder service alarm" );
    if (!isReminderServiceAlarmSet ( context )) {
        AlarmManager alarmManager = (AlarmManager) context.getApplicationContext ().getSystemService ( Context.ALARM_SERVICE );
        Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
        intent.setAction ( REMINDER_INTENT_ACTION );
        PendingIntent pendingIntent;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE );
        } else {
            pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, 0 );
        }
        alarmManager.setRepeating ( AlarmManager.RTC_WAKEUP, getReminderTriggerTime (), REMINDER_INTERVAL, pendingIntent );
        Log.d ( TAG, "Reminder service alarm setup completed" );
    }
}

查询告警是否已设置:

private static boolean isReminderServiceAlarmSet ( Context context ) {
    Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
    intent.setAction ( REMINDER_INTENT_ACTION );
    boolean isBackupServiceAlarmSet;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE );
        isBackupServiceAlarmSet = (PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE ) != null);
    } else {
        PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_NO_CREATE );
        isBackupServiceAlarmSet = (PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_NO_CREATE ) != null);
    }
    Log.d ( TAG, "Reminder service alarm is " + (isBackupServiceAlarmSet ? "" : "not ") + "set already" );
    return isBackupServiceAlarmSet;
}

取消之前设置的闹钟:

public static void cancelReminderServiceAlarm ( Context context ) {
    Log.d ( TAG, "Reminder service alarm canceled" );
    AlarmManager alarmManager = (AlarmManager) context.getApplicationContext ().getSystemService ( Context.ALARM_SERVICE );
    Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
    intent.setAction ( REMINDER_INTENT_ACTION );
    PendingIntent pendingIntent;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE );
    } else {
        pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, 0 );
    }
    alarmManager.cancel ( pendingIntent );
    pendingIntent.cancel ();
}

希望这个答案能帮助那些瞄准Android 12 / SDK 31+应用程序的人。此外,请确保在清单中添加此权限,以调度针对上述告警的告警。

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

其他回答

我的印象是没有办法做到这一点,尽管这将是很好的。

你可以通过在某个地方记录Alarm_last_set_time来实现类似的结果,并有一个On_boot_starter BroadcastReciever:BOOT_COMPLETED之类的东西。

我做了一个简单(愚蠢与否)的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;)

试试吧;)

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

你可以在这里了解更多关于AlarmManager及其工作的信息。但这里有一个简单的答案

你可以看到AlarmManager基本上在未来的某个时间安排一个PendingIntent。所以为了取消预定的Alarm,你需要取消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,如果PendingIntent不存在,它将返回null。如果它已经存在,则返回对现有的PendingIntent的引用

如果你的目标是Android 12(即目标SDK 31),那么,对于AlarmManager, PendingIntent不能在没有Mutable或Immutable标志的情况下创建。如果没有这个可变性标志,应用程序将抛出一个运行时错误。有关这方面的更多详细信息,请参阅本文档。下面的代码片段对我来说是有用的,它将帮助那些将应用程序定位于Android 12的人。

创建告警:

public static void setupReminderServiceAlarm ( Context context ) {
    Log.d ( TAG, "Trying to setup reminder service alarm" );
    if (!isReminderServiceAlarmSet ( context )) {
        AlarmManager alarmManager = (AlarmManager) context.getApplicationContext ().getSystemService ( Context.ALARM_SERVICE );
        Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
        intent.setAction ( REMINDER_INTENT_ACTION );
        PendingIntent pendingIntent;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE );
        } else {
            pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, 0 );
        }
        alarmManager.setRepeating ( AlarmManager.RTC_WAKEUP, getReminderTriggerTime (), REMINDER_INTERVAL, pendingIntent );
        Log.d ( TAG, "Reminder service alarm setup completed" );
    }
}

查询告警是否已设置:

private static boolean isReminderServiceAlarmSet ( Context context ) {
    Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
    intent.setAction ( REMINDER_INTENT_ACTION );
    boolean isBackupServiceAlarmSet;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE );
        isBackupServiceAlarmSet = (PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE ) != null);
    } else {
        PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_NO_CREATE );
        isBackupServiceAlarmSet = (PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_NO_CREATE ) != null);
    }
    Log.d ( TAG, "Reminder service alarm is " + (isBackupServiceAlarmSet ? "" : "not ") + "set already" );
    return isBackupServiceAlarmSet;
}

取消之前设置的闹钟:

public static void cancelReminderServiceAlarm ( Context context ) {
    Log.d ( TAG, "Reminder service alarm canceled" );
    AlarmManager alarmManager = (AlarmManager) context.getApplicationContext ().getSystemService ( Context.ALARM_SERVICE );
    Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
    intent.setAction ( REMINDER_INTENT_ACTION );
    PendingIntent pendingIntent;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE );
    } else {
        pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, 0 );
    }
    alarmManager.cancel ( pendingIntent );
    pendingIntent.cancel ();
}

希望这个答案能帮助那些瞄准Android 12 / SDK 31+应用程序的人。此外,请确保在清单中添加此权限,以调度针对上述告警的告警。

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

刚找到另一个解决办法,似乎对我有用

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