简体   繁体   中英

AlarmManager responding at wrong time

Sorry if answered before, but i looked everywhere but didn't get the proper solution

I am using AlarmManager to automatically fire a notification at 9am everyday, but when i try to run it on emulator it executes immediately, and every half hour (31-32min to be precise) after that instead of only once at 9am everyday.

Any ideas why? help appreciated.

code is as below:

public class Home extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_bsheet);

    notificationAlert(savedInstanceState);

}

    private void notificationAlert(Bundle savedInstanceState) {

    AlarmManager manager;
    PendingIntent pendingIntent;
    Intent intent=new Intent(Home.this, Notify.class);
    manager=(AlarmManager)getSystemService(ALARM_SERVICE);
    pendingIntent=PendingIntent.getService(Home.this,
            0, intent, 0);
    GregorianCalendar gcal = new GregorianCalendar();
    gcal.set(Calendar.HOUR_OF_DAY, 9);
    gcal.set(Calendar.MINUTE, 0);
    gcal.set(Calendar.SECOND, 0);
    gcal.set(Calendar.MILLISECOND, 0);

    long initTime = gcal.getTimeInMillis();

    manager.setRepeating(AlarmManager.RTC_WAKEUP, initTime,
            24*60*60*1000, pendingIntent);
}

}

cheers,

EDIT: my intention is that, once the app is installed, it fires this alarm at 9am. i have put the alarm in the onCreate, so im not sure if the alarm is only being created everytime i start the app and something weird is happening when i hide the app... again insight would be appreciated!

try this :

    Calendar currentTime = Calendar.getInstance();
    Calendar alarmTime = Calendar.getInstance();
    currentTime.set(Calendar.HOUR_OF_DAY, 9;
    currentTime.set(Calendar.MINUTE, 0);
    currentTime.set(Calendar.SECOND, 0);
    currentTime.set(Calendar.MILLISECOND, 0);
    if (alarmTime.compareTo(currentTime) <= 0) {
// check for time
alarmTime.add(Calendar.DATE, 1);
}

Intent intent = new Intent(getBaseContext(), Receiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
    getBaseContext(), 1, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime.getTimeInMillis(),
                        AlarmManager.INTERVAL_DAY, pendingIntent);
manager.setRepeating(AlarmManager.RTC_WAKEUP, initTime, 24*60*60*1000, pendingIntent);

Alarm manager will fire immidiatly if initTime < System.currentTimeMillis()

from docs :

If the time occurs in the past, the alarm will be triggered immediately, with an alarm count depending on how far in the past the trigger time is relative to the repeat interval.

According to the code you've provided, gcal.getTimeInMillis() will return millisecods corresponding to Today 9.00 . So if you'll try to run your code after this time, initTime will be less then current system time which triggers immidiate run of AlarmManager.

To fix this, for example, you can add one day to your calendar before passing its gcal.getTimeInMillis() if it is already in past so it will point to Tomorrow 9.00 to let it run tomorrows morning

Update1

Tried code like this and it worked as expected for me - fired service every 10 seconds:

    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    initManager();
}
private void initManager() {
    AlarmManager manager;
    PendingIntent pendingIntent;
    Intent intent = new Intent(this, NotifyService.class);
    manager=(AlarmManager)getSystemService(ALARM_SERVICE);
    pendingIntent=PendingIntent.getService(this, 0, intent, 0);

    long initTime = System.currentTimeMillis() + 5000;

    manager.setRepeating(AlarmManager.RTC_WAKEUP, initTime,
            10*1000, pendingIntent);        
}

However you can use another option: there is AlarmManager.set() method You can fire it like this

long runTime = /* your calendar time + 24 hours in millis*/
manager.set(AlarmManager.RTC_WAKEUP, runTime, pendingIntent);       

so it will fire your service at runTime . And then in the service invoke the same method with recalculated runTime for another day so it could look something like that:

public MainActivity extends Activity{

    protected onCreate(Bundle bundle){
        ....
        initManager();
    }

    private initManager(){
        ...
        long runTime = /* time of your first alarm/notification/whatever you develope */

        Intent intent = new Intent(this, NotifyService.class);
        pendingIntent=PendingIntent.getService(this, 0, intent, 0);
        manager.set(AlarmManager.RTC_WAKEUP, runTime, pendingIntent);
    }
}

And the service:

public NotifyService extends Service{
    ...
    public int onStartCommand(...){
         ...
        /* do stuff */

        Intent intent = new Intent(getApplicationContext(), NotifyService.class);
        pendingIntent=PendingIntent.getService(this, 0, intent, 0);
        long runTime = /* recalculate it according to the next time of firing this service*/
        manager.set(AlarmManager.RTC_WAKEUP, runTime, pendingIntent);

    }

}

So your service will register an intent in AlarmManager itself everytime the service fires.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM