Android AlarmManager after reboot
Asked Answered
O

1

30

I have a set of alarms that I need to keep after reboot. I've tried using on an boot receiver but they won't start again. I'm not sure if I understand the boot receiver and how to then restart all the alarms. I already have one receiver for my notifications, but don't know whether I can use the same receiver or if I need a new one?

Could anyone point me to any good tutorials or help me out?

Cheers

Code :

    DatabaseHandler db = new DatabaseHandler(this);  
    List<UAlarm> alarms = db.getAllAlarms();        
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);  
    for (UAlarm ua : alarms) {  
        String programme = ua.getTitle();  
        String startTime = ua.getStart();  
        String endTime = ua.getEnd();  
        String nowPlaying = ua.getChannel();  
        db.addAlarm(new UAlarm(programme, startTime, endTime, nowPlaying, ""));  
        final UAlarm ut = new UAlarm();  
        ut.setTitle(programme);  
        ut.setStart(startTime);  
        ut.setEnd(endTime);  
        ut.setChannel(nowPlaying);  
        ut.setId(db.getLastEntered());  
        String [] bla = startTime.split(":");  
        int hour = Integer.parseInt(bla[0].trim());  
        int minute = Integer.parseInt(bla[1].trim());  
        minute -= 2;  
        Calendar cal = Calendar.getInstance();  
        cal.set(Calendar.HOUR_OF_DAY, hour);  
        cal.set(Calendar.MINUTE, minute);  
        Intent intenta = new Intent(this, NotificationMenu.class);  
        String name = programme;  
        intenta.putExtra("name", name);  
        intenta.putExtra("id", db.getLastEntered());  
          PendingIntent pendingIntent = PendingIntent.getBroadcast(this, ua.getId(),  
            intenta, PendingIntent.FLAG_CANCEL_CURRENT);  
          am.set(AlarmManager.RTC_WAKEUP,  
            cal.getTimeInMillis(), pendingIntent);      
    }  
}  

with NotificationMenu being the notifications, which is why I'm using the AlarmManager

Oleson answered 20/9, 2012 at 12:36 Comment(0)
P
49

I'm not sure if I understand the boot receiver and how to then restart all the alarms.

Just call your code to call setRepeating() (or whatever) on AlarmManager.

For example, in this sample project, PollReceiver is set to receive BOOT_COMPLETED. In onReceive(), it reschedules the alarms:

package com.commonsware.android.schedsvc;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;

public class PollReceiver extends BroadcastReceiver {
  private static final int PERIOD=5000;

  @Override
  public void onReceive(Context ctxt, Intent i) {
    scheduleAlarms(ctxt);
  }

  static void scheduleAlarms(Context ctxt) {
    AlarmManager mgr=
        (AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);
    Intent i=new Intent(ctxt, ScheduledService.class);
    PendingIntent pi=PendingIntent.getService(ctxt, 0, i, 0);

    mgr.setRepeating(AlarmManager.ELAPSED_REALTIME,
                     SystemClock.elapsedRealtime() + PERIOD, PERIOD, pi);
  }
}
Pule answered 20/9, 2012 at 12:39 Comment(29)
Thanks for sharing but why am I not seeing BOOT_COMPLETED in your code @CommonsWare?Vasta
@fuzzybee: You apparently failed to click on the hyperlink in the answer to examine the entire project, including its manifest.Pule
@Pule is AlarmManager best way to get interval updates, There are few other ways to implement it like TimerTask etc. Which should we use???Hypothermia
For me its sending one more time additionally,while we switch on our device alsoAnodize
+1 for implementing your OWN external link. Makes it a more reliable answer in my opinion.Premer
I feel it's important to point out that specifying 0 for the flags parameter in PendingIntent.getService() will prevent extra's from being passed to the receiver.Novak
@SomeoneSomewhere: I'm not aware that this is the case. It will prevent extras from any existing matching PendingIntent being changed.Pule
This is too weird, yesterday my app was unable to read a string with Intent.getStringExtras() or Bundle.getString() - until I started to use PendingIntent.FLAG_UPDATE_CURRENT Today, that's not the case. Sorry - I didn't mean to mislead but I guess the Twilight Zone is real :-DNovak
hmmm, no I reproduced it again... I was unable to pull a string out of a bundle until I specified PendingIntent.FLAG_UPDATE_CURRENTNovak
@SomeoneSomewhere: Well, again, 0 means "don't update the extras". So if you didn't have an extra with that key when the PendingIntent was first created, you may not wind up with that extra when you try to create an equivalent PendingIntent later. If you're using extras, using one of the flags (e.g., FLAG_UPDATE_CURRENT) is a good idea. If you are not using extras, you don't need it. In my sample, I am not using extras.Pule
yeah I was thinking that too, but at the moment my app cancels all of its alarms whenever it is launched. So when it sets alarms any alarm should be "fresh" and not update an existing alarm. I wish it were possible to list all alarms currently set.Novak
If it is not working for someone then please be sure that you included permission <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>Denmark
@Pule Is there anything in this solution I should be worried about regarding the wakelock ? I want to do something similar but the service might run for a while before it's done.Milford
(My current code only runs once every boot and is using startWakefulService from a WakefulBroadcastReceiver, due to some things I read about the device sleeping before the service starts)Milford
@Pablo: If you are not handling your own WakeLock, but instead are using the one in WakefulBroadcastReceiver, and if "run for a while before it's done" is just a matter of a long-running onHandleIntent(), you should be OK, if your work is pretty sure to be done in less than a minute. That is the maximum time WakefulBroadcastReceiver will hold its WakeLock before automatically releasing it. If your work might be longer than that, then WakefulBroadcastReceiver and IntentService might not be the best pattern for you.Pule
@Pule I am not handling my own WakeLock on the service. The operation is likely to run under 1 minute, but I start Volley requests in the OnHandleIntent . Are there any problems due to its asynchronous nature?Milford
@Pablo: Yes, if that work might run past the end of onHandleIntent(). That's one of the many reasons why I don't use Volley -- it's not sufficiently flexible for use from both the UI and background threads. There are recipes for making synchronous requests with Volley, but they seemed like they were workarounds for a fundamental library limitation. I'm an OkHttp fan. :-)Pule
@Pule I will give OkHttp a look, then. Many thanks! :)Milford
@Pule I downloaded the sample to try to compare what I am doing wrong. I added a log Log.d(getClass().getSimpleName(), "startup. action="+i.getAction()); in PollReceiver.onReceive. Last night I ran it once(only once), went to bed happy that I would be able to debug this. This morning, it's not working at all..no logs at all when I start it. I will be adding more and more detail to this post as I debug further #63294400Clyve
@DeanHiller: This answer is from 2012. Nowadays, Doze mode, app standby, and manufacturer power limiters really restrict AlarmManager and other periodic background triggers.Pule
@Pule oh, I am not trying to do a repeat alarm. I am only trying to reschedule alarms that are no longer scheduled after a reboot(or somehow save them before a reboot). Is that possible? ie. I scheduled notifications to go out and I think a reboot clears those. (some of these are 2 months from the date the phone is rebooted).Clyve
@DeanHiller: "I scheduled notifications to go out and I think a reboot clears those" -- yes, that is still the case AFAIK.Pule
@Pule so is the only way to reschedule by creating a service? In your example, that 'seems' to work in that the service always starts up ...... even though I don't want a service running for my app(lol).Clyve
@Pule and you could post an answer in my SO post and I'll mark it correct either way! because this has been helpful and you deserve it.Clyve
@DeanHiller: "so is the only way to reschedule by creating a service?" -- frankly, I have steered clear of AlarmManager for a few years. Again, this answer is from 2012, back when life was simpler (anyone could do anything with AlarmManager, no Doze mode, no murder hornets, etc.). Back in the day, rescheduling from a boot-time receiver worked, but I have not tried any of this in a while.Pule
@Pule any advice then on a new path forward? (I am only 50 hours into android development...after work in my spare time).Clyve
@DeanHiller: I would not recommend AlarmManager to newcomers to Android. If you are trying to do a bit of work every so often, consider WorkManager.Pule
@CommonsWare. sweet, thanks!!! I am just trying to make sure my notifications go off when the user wants them too(ie. it is setup by the user so they would hate for them not to get what they scheduled). thanks!Clyve
@DeanHiller: "I am just trying to make sure my notifications go off when the user wants them too" -- to be honest, I would not recommend that a newcomer to Android write an app with that functionality. For that, you would definitely need to use AlarmManager, and AlarmManager is not simple anymore.Pule

© 2022 - 2024 — McMap. All rights reserved.