ron*_*ron 219 android alarmmanager
当我的应用程序启动时,我希望它检查是否已设置并运行特定警报(通过AlarmManager注册).谷歌的结果似乎表明没有办法做到这一点.这仍然是正确的吗?我需要进行此检查,以便在采取任何操作创建新警报之前通知用户.
Chr*_*ght 311
关注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);
Run Code Online (Sandbox Code Playgroud)
您检查它是否处于活动状态的方式是:
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");
}
Run Code Online (Sandbox Code Playgroud)
这里的关键是FLAG_NO_CREATEjavadoc中描述的:( if the described PendingIntent **does not** already exists, then simply return null而不是创建一个新的)
Jac*_*eng 109
对于可能需要这个的人来说,这是一个答案.
使用 adb shell dumpsys alarm
您可以知道已经设置了警报以及它们何时会发出警报和间隔.此外,还会调用此警报的次数.
dea*_*ish 49
带接收器的工作示例(最重要的答案就是行动).
//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...");
Run Code Online (Sandbox Code Playgroud)
值得一提的是:
如果创建应用程序稍后(进程)重新检索相同类型的PendingIntent(相同的操作,相同的Intent - 动作,数据,类别,组件,标志),它将接收表示同一令牌的PendingIntent,如果它仍然有效,并且因此可以调用cancel()来删除它.
简而言之,您的PendingIntent应该具有相同的功能(操作和意图的结构)来控制它.
big*_*_29 44
请注意警报管理器的文档中的引用:
如果已经安排了此Intent的警报(Intent.filterEquals定义了两个意图相等),那么它将被删除并替换为此.
如果您正在尝试决定是否创建警报,请不要打扰询问警报是否存在.只需在每次应用启动时创建它.您将替换您配置的任何过去警报.
如果您正在尝试计算先前创建的警报剩余时间,或者您确实需要知道此警报是否存在,则需要采用不同的方法.要回答这些问题,请考虑在创建警报时保存共享的pref数据.您可以在设置闹钟时存储时钟时间戳,预计闹钟关闭的时间以及重复周期(如果您设置了重复闹钟).
HiB*_*HiB 10
我有2个闹钟.我使用intent而不是action来识别事件:
Intent i = new Intent(context, AppReciever.class);
i.putExtra("timer", "timer1");
Run Code Online (Sandbox Code Playgroud)
事实上,对于diff extras,意图(和警报)不会是唯一的.因此,为了能够识别哪个警报是活动的,我必须定义diff requestCode-s:
boolean alarmUp = (PendingIntent.getBroadcast(context, MyApp.TIMER_1, i,
PendingIntent.FLAG_NO_CREATE) != null);
Run Code Online (Sandbox Code Playgroud)
以下是警报的创建方式:
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);
Run Code Online (Sandbox Code Playgroud)
小智 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);
}
Run Code Online (Sandbox Code Playgroud)
If you target Android 12 (i.e) Target SDK 31, then, for AlarmManager, PendingIntent cannot be created without a Mutable or an Immutable flag. Without this Mutability flag, the application will throw a runtime error. See this documentation for more details about this. The following code snippet is working for me and will help fellow people who target their application for Android 12.
For creating an Alarm:
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" );
}
}
Run Code Online (Sandbox Code Playgroud)
For checking whether the alarm is already set or not:
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;
}
Run Code Online (Sandbox Code Playgroud)
For cancelling the alarm which was set earlier:
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 ();
}
Run Code Online (Sandbox Code Playgroud)
Hope this answer helps people who target their application for Android 12 / SDK 31+. Also, make sure to add this permission in Manifest for scheduling alarms targeting the above.
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
Run Code Online (Sandbox Code Playgroud)
小智 5
我制作了一个简单(愚蠢与否)的 bash 脚本,它从 adb shell 中提取 longs,将它们转换为时间戳并以红色显示。
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;)
Run Code Online (Sandbox Code Playgroud)
尝试一下 ;)
尽管这里的几乎每个人都给出了正确的答案,但是没有人解释“警报”的依据是什么
您实际上可以AlarmManager在这里了解更多信息及其工作原理。但这是快速答案
您AlarmManager基本上会看到PendingIntent将来某个时间的时间表。因此,要取消预定的警报,您需要取消PendingIntent。
创建时始终注意两件事 PendingIntent
PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
Run Code Online (Sandbox Code Playgroud)
PendingIntent现在,要检查警报是否已安排好或要取消警报,您只需要访问该警报即可PendingIntent。如果您使用相同的请求代码并按FLAG_NO_CREATE如下所示使用,则可以完成此操作
PendingIntent pendingIntent=PendingIntent.getBroadcast(this,REQUEST_CODE,intent,PendingIntent.FLAG_NO_CREATE);
if (pendingIntent!=null)
alarmManager.cancel(pendingIntent);
Run Code Online (Sandbox Code Playgroud)
随着FLAG_NO_CREATE它会返回null,如果PendingIntent不存在。如果已经存在,则返回对现有对象的引用PendingIntent
小智 0
我的印象是没有办法做到这一点,但那会很好。
您可以通过在某处记录 Alarm_last_set_time 并使用 On_boot_starter BroadcastReciever:BOOT_COMPLETED 之类的东西来实现类似的结果。
| 归档时间: |
|
| 查看次数: |
92590 次 |
| 最近记录: |