Search code examples
javaandroidandroid-servicealarmmanagerandroid-pendingintent

Restart at exact time?


I'd like to make my app restart everyday at 20:00, but it's not working as expected. The first execution happens as scheduled, but afterwards it restarts endlessly.

I expected the app to forget about the PendingIntent and added the PendingIntent.FLAG_ONE_SHOT, but it didn't take any effect.

I guess, I'm missing an important flag that ends the PendingIntent after the first execution, but couldn't find anything so far.

Any ideas? Thanks in advance!

App.java (works)

// Create the calendar object
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 20);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);

// Schedule the restart
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, RestartReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);

RestartReceiver.java (works partly)

public class RestartReceiver extends BroadcastReceiver {   
    static Context context;

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Restart!", Toast.LENGTH_LONG).show(); // works one time

        Util.restart(App.getInstance().getApplicationContext()); // executed endlessly
    }
}

Util.java (copied 1:1 from here, works when not called by the AlarmManager)

    try {
        //check if the context is given
        if (c != null) {
            //fetch the packagemanager so we can get the default launch activity 
            // (you can replace this intent with any other activity if you want
            PackageManager pm = c.getPackageManager();
            //check if we got the PackageManager
            if (pm != null) {
                //create the intent with the default start activity for your application
                Intent mStartActivity = pm.getLaunchIntentForPackage(
                        c.getPackageName()
                );
                if (mStartActivity != null) {
                    mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    //create a pending intent so the application is restarted after System.exit(0) was called. 
                    // We use an AlarmManager to call this intent in 100ms
                    int mPendingIntentId = 223344;
                    PendingIntent mPendingIntent = PendingIntent
                            .getActivity(c, mPendingIntentId, mStartActivity,
                                    PendingIntent.FLAG_CANCEL_CURRENT);
                    AlarmManager mgr = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
                    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
                    //kill the application
                    System.exit(0);
                } else {
                    Log.e(TAG, "Was not able to restart application, mStartActivity null");
                }
            } else {
                Log.e(TAG, "Was not able to restart application, PM null");
            }
        } else {
            Log.e(TAG, "Was not able to restart application, Context null");
        }
    } catch (Exception ex) {
        Log.e(TAG, "Was not able to restart application");
    }

Solution

  • Probably not the best solution, but it works:

    I've another Service that runs every minute and restarts if currentTime equals restartTime.