24

Edit: Clarified the question based on CommonsWare's answer

We're scheduling an an alarm via AlarmManager to trigger every 60 seconds. When our application is killed our alarms seem to no longer execute. Is there a way to make these alarms persist even when the application is killed manually or by the system?

This is a problem for us because we have a widget application that displays the time. This means we need to update the time every minute. To get around the 30 minute update limit on the onUpdate method of AppWidgetProvider we use AlarmManager. It usually works pretty well, but some users have reported the time going out of sync. After talking to several of them, my suspicion is that our application is being killed manually via a task killer app or Android is itself is killing our app.

Any other alternate solutions to the root problem (keeping the time in sync in a widget) welcome as well.

Here is the code we execute to schedule our alarm:

Intent intent = new Intent(UPDATE_TIME);
PendingIntent pIntent = PendingIntent.getBroadcast(ctx,
  0 /* no requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT );

// get alarm params
Date d = new Date();
long timeTilMinuteChange = 60*1000-d.getSeconds()*1000;
long startTime = System.currentTimeMillis() + + timeTilMinuteChange;

AlarmManager am = (AlarmManager) ctx.getSystemService(Context.
am.cancel(pIntent);
am.set(AlarmManager.RTC, System.currentTimeMillis(), pIntent);
        am.setRepeating(AlarmManager.RTC, startTime, 60000, pIntent);
christoff
  • 587
  • 1
  • 6
  • 17
  • I think that the Alarm Manager is not being killed, but maybe the data is becoming stale. Are you using static variables ? Remember the appwidget process can and will be shutdown by Android (it's a receiver) are you using any variables that are bound to the AppWidgetProvider class ? – Efi MK Feb 01 '12 at 20:04
  • I'm not using static variables, but I am using a static class. Essentially the way it works is our AppWidgetProvider calls TimeManager.start(context). TimeManager.start sets a repeating alarm. – christoff Feb 01 '12 at 23:29
  • @EfiMK I know its a very old post but as I couldn't find answers anywhere else so please guide on the problem of using static variables in appwidgetprovider class. – Atihska Jul 22 '13 at 23:49

2 Answers2

14

Whenever our application is killed, the AlarmManager is also killed.

AlarmManager is not killed. Your alarm, however, is canceled. If the user force-stops or task-kills you, your alarms are unscheduled. On Android 3.1+, if the user force-stops you, nothing of your code will run again until the user manually launches one of your activities.

After talking to several of them, my suspicion is that our application is being killed manually via a task killer app or Android is itself is killing our app.

Ideally, your app should not be written in such a way that Android would have any cause to get rid of you. For something like what you describe, you should either using a getBroadcast() PendingIntent pointing to a manifest-registered BroadcastReceiver, or you should be using a getService() PendingIntent pointing to an IntentService. In either case, your code will run briefly, and then your process will be eligible for reclamation by Android without issue should the need arise.

Task killers, whether manual or automatic, seem a far more likely culprit of alarms being canceled, IMHO.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Re Alarm canceled: Thanks for the clarification. I asked this on the Android team office hours g+ hangout and they even seemed confused about this behavior. Is it documented anywhere? – christoff Feb 01 '12 at 23:37
  • Re getBroadcast / getService Pending Intent: I am using getBroadcast() like you describe. I added some relevant code above. – christoff Feb 01 '12 at 23:40
  • Re Android 3.1: What about services? I just tried killing an app with my Galaxy Nexus and one of it's services was automatically restarted. – christoff Feb 01 '12 at 23:42
  • 2
    Do you have any suggestions on how I should deal with my alarm being cancelled? One of the Android team members suggested rescheduling the alarm in a service because the system will automatically restart it. – christoff Feb 01 '12 at 23:45
  • Well this absolutely sucks. Android should restart a repeating alarm even it's killed manually or by some task manager. – Johann Apr 29 '13 at 07:52
1

About the alarm manager in the Docs - the explanation is somewhat confusing and I honestly still don't get it fully. I have this bit of code for the widget part that solved the problem in my case.

package com.test.mytestwidget;

import java.util.Calendar;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;  

public class MyWidgetProvider extends AppWidgetProvider {   

    private PendingIntent service = null;  

    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);                

        final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);  

        final Calendar TIME = Calendar.getInstance();  
        TIME.set(Calendar.MINUTE, 0);  
        TIME.set(Calendar.SECOND, 0);  
        TIME.set(Calendar.MILLISECOND, 0);  

        final Intent i = new Intent(context, UpdateWidgetService.class);  

        if (service == null)  
        {  
            service = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);  
        }  

        m.setRepeating(AlarmManager.RTC, TIME.getTime().getTime(), 30000, service);  

     }

     @Override  
     public void onDisabled(Context context)  
     {              
         final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);  

         m.cancel(service);  
         super.onDisabled(context);
     }      

}
Scalarr
  • 746
  • 7
  • 26