安排警报管理器每周四运行一个方法

时间:2017-11-15 15:41:38

标签: c# xamarin.forms xamarin.android alarmmanager

例如,我希望每周四中午12点发出警报 我该怎么做?

我有一些实施但没有正常工作,我的代码,今天是星期三15,如果将手机的日期改为16星期四,应用程序什么都不做,如果我改变手机的日期在下周三22号电话发出通知,但只能在周四发送。

这是我的代码:

MainActivity:

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());

    }

BootReceiver:

[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);
    }
}

AlarmReceiver:

[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)
        {

        }
    }
}

1 个答案:

答案 0 :(得分:2)

对于低于19的api级别,您应该使用AlarmManager.setRepeating(),并且您的警报将在指定时间准确触发。但正如document所说,当你的设备api等级为19及以上时,这将不再起作用。

  

注意:从API 19(KITKAT)开始,警报传递不准确:操作系统将移动警报以最小化唤醒和电池使用。有新的API支持需要严格交付保证的应用程序;请参阅setWindow(int,long,long,PendingIntent)和setExact(int,long,PendingIntent)。 targetSdkVersion早于API 19的应用程序将继续查看之前在请求时准确传递所有警报的行为。

同时使用alarmManager.SetExact()方法:

  

警报将尽可能地传递到请求的触发时间。

因此,如果你想要实现精确的重复警报,那么@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);
}

更新:

打瞌睡背后的想法是试图防止电池耗尽。重复警报会耗尽电池,因此在Android 6中删除了通过传递额外参数重复警报的内置方式。因此,它需要您手动重新安排警报。

您可以在发生警报之前立即重新安排警报,然后再做任何可能出错的事情,并防止警报被重新安排。

更新2:

关于使用SetExactAndAllowWhileIdle方法实现重复闹钟的简单演示,希望这可以帮助您。

第一次设置闹钟:

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();
    }
}