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


当前回答

我用android jetpack workManager做了一个变通。

与其直接在alarmManager中设置警报,不如在workManager中设置work,在那里您可以设置触发时间(在workManager中设置触发时间),并为该work添加一个标签。当工作触发时,可设置并触发报警。

为了回答您的问题,您只需通过.addTag("something")向作品添加标签,然后在检查活动作品时使用.getWorkInfosByTag("something")

其他回答

根据我的经验,在最新版本的Android中,我认为它只允许广播消息唤醒警报,而不是直接启动服务。看看这个链接:https://developer.android.com/training/scheduling/alarms,上面写着:

报警器具有以下特点:

它们允许你在设定的时间和/或间隔内发射intent。 您可以将它们与广播接收器结合使用以启动服务和执行其他操作。

第二句话的关键词是“连词”。它明确指出,警报是为Broadcast设计的(这意味着不是为直接启动服务而设计的)。我尝试了几个小时使用一个PendingIntent与getService(),但不能让它工作,即使我确认挂起的意图是正确地使用:

pendingIntent.send(0);

对于“targetSdkVersion 29”,这没有工作..[不会触发onStartCommand()]:

Intent launchIntent = new Intent(context, MyService.class);
launchIntent.putExtra(Type.KEY, SERVER_QUERY);    
PendingIntent pendingIntent =
                PendingIntent.getService(context, 0, launchIntent, 0);

我可以验证警报正在运行使用:

adb shell dumpsys alarm | grep com.myapp

然而,这确实奏效了:

public static class AlarmReceiverWakeup extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive Alarm wakeup");
        startService(context);
    }
}


public static void scheduleAlarmWakeup(Context context) {

    Intent broadcastIntent = new Intent(context, AlarmReceiverWakeup.class);
    broadcastIntent.putExtra(Type.KEY, SERVER_QUERY);    
    PendingIntent pendingIntent =
                    PendingIntent.getBroadcast(context, 0, broadcastIntent, 0);
    AlarmManager alarmManager =
                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    // NOTE: using System.currentTimeMillis() fails w/ELAPSED_REALTIME_WAKEUP 
    //     use SystemClock.elapsedRealtime() instead
    alarmManager.setRepeating(
                AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime()+5000,
                AlarmManager.INTERVAL_FIFTEEN_MINUTES/4,
                getAlarmPendingIntent(context)
    );
}

顺便说一下,这是Broadcast Receiver的AndroidManifest.xml条目:

<receiver android:name=".ServerQueryService$AlarmReceiverWakeup"
    android:enabled="true">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</receiver>

对于其他可能需要这个的人,这里有一个答案。

使用adb shell dumpsys警报

你可以知道闹铃已经设置好了,什么时候闹铃和间隔时间。还有这个警报被触发的次数。

如果你的目标是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 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");

            }

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

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