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


当前回答

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

试试吧;)

其他回答

请注意Alarm Manager的set方法的文档引用:

如果已经为此意图计划了一个警报(使用 由Intent.filterEquals定义的两个意图的相等性),然后它 将被移除,并被这个替换。

如果你知道你想要闹钟设置,那么你不需要费心检查它是否已经存在。每次你的应用启动时创建它。您将用相同的意图替换任何过去的警报。

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

接收器的工作示例(上面的答案只是与动作有关)。

//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 表示相同的令牌,如果该令牌仍然有效,则可以调用 取消()来删除它。

简而言之,你的PendingIntent应该有相同的特性(操作和意图的结构)来控制它。

根据我的经验,在最新版本的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>

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

试试吧;)

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

使用adb shell dumpsys警报

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