安排警报管理器每周四 运行 一个方法
Schedule Alarm manager to run a method every Thursday
例如,我想要一个每周四中午 12 点触发的闹钟
我该怎么做?
我已经实现了某些功能但无法正常工作,使用我的代码,今天是星期三 15,如果将 phone 的日期更改为 16 星期四,如果我更改,应用程序不会执行任何操作phone 的日期为下个星期三 22 phone 发送通知,但只应在星期四发送。
这是我的代码:
主要活动:
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
AsNumAssemblyHelper.HoldAssembly();
global::Xamarin.Forms.Forms.Init(this, bundle);
ImageCircleRenderer.Init();
Intent alarmIntent = new Intent(this, typeof(AlarmReceiver));
PendingIntent pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();
//AlarmType.RtcWakeup – it will fire up the pending intent at a specified time, waking up the device
alarmManager.SetRepeating(AlarmType.RtcWakeup,BootReceiver.FirstReminder(), BootReceiver.reminderInterval, pending);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, 0);
LoadApplication(new App());
}
引导接收器:
[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver
{
//the interval currently every one minute
//to set it to dayly change the value to 24 * 60 * 60 * 1000
public static long reminderInterval = AlarmManager.IntervalDay * 7;
//public static long reminderInterval = 30 * 1000;
public static long FirstReminder()
{
Java.Util.Calendar calendar = Java.Util.Calendar.Instance;
calendar.Set(Java.Util.CalendarField.DayOfWeek, Calendar.Thursday);
return calendar.TimeInMillis;
}
public override void OnReceive(Context context, Intent intent)
{
Console.WriteLine("BootReceiver: OnReceive");
var alarmIntent = new Intent(context, typeof(AlarmReceiver));
var pending = PendingIntent.GetBroadcast(context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
alarmManager.SetRepeating(AlarmType.RtcWakeup, FirstReminder(), reminderInterval, pending);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, 0);
}
}
报警接收器:
[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
try
{
var title = "Something";
var message = "Something";
Intent backIntent = new Intent(context, typeof(MainActivity));
backIntent.SetFlags(ActivityFlags.NewTask);
var builder =
new Notification.Builder(context)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.icon)
.SetDefaults(NotificationDefaults.All);
var notification = builder.Build();
var manager = NotificationManager.FromContext(context);
manager.Notify(1331, notification);
}
}
catch (Exception)
{
}
}
}
对于 api 低于 19 的级别,您应该使用 AlarmManager.setRepeating()
并且您的警报将在指定时间准确触发。但正如 document 所说,当您的设备 api 级别为 19 级及以上时,这将不再有效。
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
同样在使用 alarmManager.SetExact()
方法时:
The alarm will be delivered as nearly as possible to the requested trigger time.
所以如果你想实现精确的重复报警,如@Dus said这里有两个建议:
- 接受时间延迟(但可以考虑使用更推荐的 JobSchedular,这样可以节省电量)。
或者:
- 使用 SetExactAndAllowWhileIdle 这可能会导致您的电池出现问题(谨慎使用,过多的警报对您的电池不利)。
此方法不重复,因此您必须在 pendingIntent 打开的服务上声明下一个作业 运行。
将 Dus 的代码转换为 C#:
AlarmManager alarmManager = (AlarmManager)this.GetSystemService(Context.AlarmService);
var ALARM_TYPE = AlarmType.RtcWakeup;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M)
{
alarmManager.SetExactAndAllowWhileIdle(ALARM_TYPE, calendar.TimeInMillis, pendingIntent);
}
else if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
{
alarmManager.SetExact(ALARM_TYPE, calendar.TimeInMillis, pendingIntent);
}
else if
{
alarmManager.Set(ALARM_TYPE, calendar.TimeInMillis, pendingIntent);
}
更新:
打瞌睡的想法是试图防止耗尽电池电量。重复警报会耗尽电池电量,因此在 android6 中删除了通过传递额外参数来重复警报的内置方法。因此需要您手动重新安排警报。
您可以在警报触发时立即重新安排警报,然后再做任何可能出错并阻止警报被重新安排的事情。
更新 2:
一个使用SetExactAndAllowWhileIdle
方法实现重复闹钟的简单demo,希望对您有所帮助。
第一次设置闹钟:
var intent = new Intent(this, typeof(RepeatingAlarm));
var source = PendingIntent.GetBroadcast(this, 0, intent, 0);
// Schedule the alarm!
var am = (AlarmManager)GetSystemService(AlarmService);
//After 15s, use the RepeatingAlarm to show a toast
am.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime() + 15 * 1000, source);
在RepeatingAlarm
中:
[BroadcastReceiver]
public class RepeatingAlarm : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
//Every time the `RepeatingAlarm` is fired, set the next alarm
var intentForRepeat = new Intent(context, typeof(RepeatingAlarm));
var source = PendingIntent.GetBroadcast(context, 0, intent, 0);
var am = (AlarmManager)Android.App.Application.Context.GetSystemService(Context.AlarmService);
am.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime() + 15 * 1000, source);
Toast.MakeText(context, "repeating_received and after 15s another alarm will be fired", ToastLength.Short).Show();
}
}
例如,我想要一个每周四中午 12 点触发的闹钟 我该怎么做?
我已经实现了某些功能但无法正常工作,使用我的代码,今天是星期三 15,如果将 phone 的日期更改为 16 星期四,如果我更改,应用程序不会执行任何操作phone 的日期为下个星期三 22 phone 发送通知,但只应在星期四发送。
这是我的代码:
主要活动:
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
AsNumAssemblyHelper.HoldAssembly();
global::Xamarin.Forms.Forms.Init(this, bundle);
ImageCircleRenderer.Init();
Intent alarmIntent = new Intent(this, typeof(AlarmReceiver));
PendingIntent pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();
//AlarmType.RtcWakeup – it will fire up the pending intent at a specified time, waking up the device
alarmManager.SetRepeating(AlarmType.RtcWakeup,BootReceiver.FirstReminder(), BootReceiver.reminderInterval, pending);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, 0);
LoadApplication(new App());
}
引导接收器:
[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver
{
//the interval currently every one minute
//to set it to dayly change the value to 24 * 60 * 60 * 1000
public static long reminderInterval = AlarmManager.IntervalDay * 7;
//public static long reminderInterval = 30 * 1000;
public static long FirstReminder()
{
Java.Util.Calendar calendar = Java.Util.Calendar.Instance;
calendar.Set(Java.Util.CalendarField.DayOfWeek, Calendar.Thursday);
return calendar.TimeInMillis;
}
public override void OnReceive(Context context, Intent intent)
{
Console.WriteLine("BootReceiver: OnReceive");
var alarmIntent = new Intent(context, typeof(AlarmReceiver));
var pending = PendingIntent.GetBroadcast(context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
alarmManager.SetRepeating(AlarmType.RtcWakeup, FirstReminder(), reminderInterval, pending);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, 0);
}
}
报警接收器:
[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
try
{
var title = "Something";
var message = "Something";
Intent backIntent = new Intent(context, typeof(MainActivity));
backIntent.SetFlags(ActivityFlags.NewTask);
var builder =
new Notification.Builder(context)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.icon)
.SetDefaults(NotificationDefaults.All);
var notification = builder.Build();
var manager = NotificationManager.FromContext(context);
manager.Notify(1331, notification);
}
}
catch (Exception)
{
}
}
}
对于 api 低于 19 的级别,您应该使用 AlarmManager.setRepeating()
并且您的警报将在指定时间准确触发。但正如 document 所说,当您的设备 api 级别为 19 级及以上时,这将不再有效。
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
同样在使用 alarmManager.SetExact()
方法时:
The alarm will be delivered as nearly as possible to the requested trigger time.
所以如果你想实现精确的重复报警,如@Dus said这里有两个建议:
- 接受时间延迟(但可以考虑使用更推荐的 JobSchedular,这样可以节省电量)。
或者:
- 使用 SetExactAndAllowWhileIdle 这可能会导致您的电池出现问题(谨慎使用,过多的警报对您的电池不利)。 此方法不重复,因此您必须在 pendingIntent 打开的服务上声明下一个作业 运行。
将 Dus 的代码转换为 C#:
AlarmManager alarmManager = (AlarmManager)this.GetSystemService(Context.AlarmService);
var ALARM_TYPE = AlarmType.RtcWakeup;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M)
{
alarmManager.SetExactAndAllowWhileIdle(ALARM_TYPE, calendar.TimeInMillis, pendingIntent);
}
else if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
{
alarmManager.SetExact(ALARM_TYPE, calendar.TimeInMillis, pendingIntent);
}
else if
{
alarmManager.Set(ALARM_TYPE, calendar.TimeInMillis, pendingIntent);
}
更新:
打瞌睡的想法是试图防止耗尽电池电量。重复警报会耗尽电池电量,因此在 android6 中删除了通过传递额外参数来重复警报的内置方法。因此需要您手动重新安排警报。
您可以在警报触发时立即重新安排警报,然后再做任何可能出错并阻止警报被重新安排的事情。
更新 2:
一个使用SetExactAndAllowWhileIdle
方法实现重复闹钟的简单demo,希望对您有所帮助。
第一次设置闹钟:
var intent = new Intent(this, typeof(RepeatingAlarm));
var source = PendingIntent.GetBroadcast(this, 0, intent, 0);
// Schedule the alarm!
var am = (AlarmManager)GetSystemService(AlarmService);
//After 15s, use the RepeatingAlarm to show a toast
am.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime() + 15 * 1000, source);
在RepeatingAlarm
中:
[BroadcastReceiver]
public class RepeatingAlarm : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
//Every time the `RepeatingAlarm` is fired, set the next alarm
var intentForRepeat = new Intent(context, typeof(RepeatingAlarm));
var source = PendingIntent.GetBroadcast(context, 0, intent, 0);
var am = (AlarmManager)Android.App.Application.Context.GetSystemService(Context.AlarmService);
am.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime() + 15 * 1000, source);
Toast.MakeText(context, "repeating_received and after 15s another alarm will be fired", ToastLength.Short).Show();
}
}