当我的应用程序启动时,我希望它检查是否已设置并运行特定警报(通过AlarmManager注册)。谷歌的结果似乎表明没有办法做到这一点。这仍然是正确的吗?我需要进行此检查,以便在采取任何措施创建新警报之前通知用户。
答案 0 :(得分:302)
关注发布的评论,这是详细的解决方案。假设你已经注册了一个具有未决意图的重复警报:
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
(而不是创建一个新的)
答案 1 :(得分:108)
对于其他可能需要此功能的人来说,这是一个答案。
使用adb shell dumpsys alarm
您可以知道警报已经设置,以及它们何时会发出警报和间隔。此外,还会调用此警报的次数。
答案 2 :(得分: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's - 动作,数据,类别, 组件,标志),它将收到一个PendingIntent 如果仍然有效,则表示相同的令牌,因此可以调用 取消()删除它。
简而言之,您的PendingIntent应具有相同的功能(操作和意图的结构)来控制它。
答案 3 :(得分:39)
注意警报管理器设置方法的文档中的this quote:
如果已安排此Intent的警报(使用 两个意图的相等性由Intent.filterEquals定义,然后它 将被移除并替换为此。
如果你知道你想要设置闹钟,那么你不需要费心去检查它是否已经存在。只需在每次应用启动时创建它。您将使用相同的Intent
替换任何过去的警报。
如果您正在尝试计算先前创建的警报剩余时间,或者您确实需要知道此警报是否存在,则需要采用不同的方法。要回答这些问题,请考虑在创建警报时保存共享的pref数据。您可以在设置闹钟时存储时钟时间戳,预计闹钟关闭的时间以及重复周期(如果设置重复闹钟)。
答案 4 :(得分:10)
我有2个闹钟。我使用extras而不是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);
答案 5 :(得分:6)
刚刚找到另一个解决方案,它似乎对我有用
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);
}
答案 6 :(得分: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;)
试试吧;)
答案 7 :(得分:3)
虽然这里的几乎每个人都给出了正确答案,但没有任何机构解释警报的工作原理
您实际上可以详细了解AlarmManager
及其工作here。但这是快速回答
您看到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
答案 8 :(得分: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");
}
答案 9 :(得分:0)
我的印象是没有办法做到这一点,但这会很好。
您可以通过在某处记录Alarm_last_set_time并使用On_boot_starter BroadcastReciever:BOOT_COMPLETED来实现类似的结果。
答案 10 :(得分:0)
根据我的经验,在更新的 Android 版本中,我认为它只允许广播消息唤醒闹钟,而不是直接启动服务。请参阅此链接:https://developer.android.com/training/scheduling/alarms,它说:
警报具有以下特征:
第二句中的有效词是“连词”。它明确指出警报是为广播设计的(这意味着不是直接启动服务)。我尝试了几个小时将 PendingIntent 与 getService() 一起使用,但无法使其正常工作,即使我确认挂起的 Intent 仅使用以下方法即可正常工作:
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)
);
}
顺便说一句,这是广播接收器的 AndroidManifest.xml 条目:
<receiver android:name=".ServerQueryService$AlarmReceiverWakeup"
android:enabled="true">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>