I have an application that automates based on the user's location. I'm now handling doze mode, since doze throws a kink in my ability to send requests in the background based on location changes. I want to give my service internet access every 9 minutes or during maintenance windows. I'm using AlarmManager and SetExactAndAllowWhileIdle, but for some reason my alarms are spamming over and over again despite me giving them a AlarmType.RtcWakeup that's in the future. My location service starts when the app starts and my service also starts/restarts when the app is terminated and when the device is rebooted.
I'm confused about when and where to set my alarm. Right now i'm setting my alarm when the location service starts. The alarms keep getting set and even fire immediately instead of the time at which I set them to fire. I'm setting SetExactAndAllowWhileIdle with AlarmType.RtcWakeup and my time looks correct. I'm event printing it out with toasts and it's clearly showing it's in the future by ~9 minutes.
When should I set the alarm? Am i not supposed to act on every OnHandleIntent I receive from the alarm? Am I setting the alarm incorrectly?
Right now i'm calling this when my location service starts:
StartAlarm_Now();
Should I instead be setting this when the app is terminated or paused?
// I'm using AlarmType.RtcWakeup, so I need to get current time in milliseconds
public static long GetDateTimesMillisecondsForToday()
{
var test = (DateTime.Now).Subtract(DateTime.Today);
var hours = test.TotalHours;
long milliseconds = (long)(test.TotalMilliseconds);
return milliseconds;
}
// Calling this will set the alarm for now. Should I ever need to do this??
public static void StartAlarm_Now()
{
string id = "Now_" + new Random().Next(1000, 9999).ToString();
StartAlarm(id, GetDateTimesMillisecondsForToday());
}
// Calling this will set the alarm for x seconds from now. This is the right way to do it?
public static void StartAlarm_SecondsFromNow(long a_secondsFromNow)
{
string id = "SecondsFromNow_" + new Random().Next(1000, 9999).ToString();
long millisecondsToUse = GetDateTimesMillisecondsForToday() + (a_secondsFromNow * 1000);
StartAlarm(id, millisecondsToUse);
}
private static void StartAlarm(string id, long a_milliseconds)
{
TimeSpan t = TimeSpan.FromMilliseconds(a_milliseconds);
string readableTime_fromMilliseconds = string.Format(
"{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms",
t.Hours,
t.Minutes,
t.Seconds,
t.Milliseconds
);
string message = "StartAlarm " + id + " readableTime_fromMilliseconds = " + readableTime_fromMilliseconds;
SCoreAppContext.Instance.Container.Get<ISCoreAppGlobal<Activity>>().SafeInvokeOnMainThread(() =>
{
Toast.MakeText(Android.App.Application.Context, message, ToastLength.Short).Show();
});
using (AlarmManager alarmManager = (AlarmManager)AppContext.GetSystemService(Context.AlarmService))
{
Intent serviceIntent = new Intent(Android.App.Application.Context, typeof(TestService));
PendingIntent pendingIntent = PendingIntent.GetService(Android.App.Application.Context, 0, serviceIntent, PendingIntentFlags.CancelCurrent);
alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, a_milliseconds, pendingIntent);
}
}
[Service(Exported = false)]
public class TestService : IntentService
{
public override void OnCreate()
{
base.OnCreate();
}
public override Android.OS.IBinder OnBind(Android.Content.Intent intent)
{
return null;
}
protected override async void OnHandleIntent(Intent intent)
{
// This part is spamming constantly while the app is running.
// Here is where I run my code that should execute when my alarm expires, right?... That's what I'm assuming, but this is spamming a LOT. And my alarms set for the future and this is getting called immediately
SCoreAppContext.Instance.Container.Get<ISCoreAppGlobal<Activity>>().SafeInvokeOnMainThread(() =>
{
Toast.MakeText(Android.App.Application.Context, "JoeyZTestService.OnHandleIntent", ToastLength.Short).Show();
});
// I read that if you want the alarm to repeat, you can set another one when this one fires. But I believe this is why mine are looping forever. So how can i repeat if not here?
// The 530 is the # of seconds in the future that the alarm should fire.
StartAlarm_SecondsFromNow(530);
}
}