Search code examples
javaandroidalarmmanagerandroid-pendingintent

Android AlarmManager RTC_WAKEUP inprecise?


I am trying to find a way to execute some code at specifics times. For this I am trying currently to just use what Android gives: the AlarmManger. When setting the time it gets executed but not exactly to when I've set the time -> There is always a delay which seems to be longer when the time is more away from the current. How can I fix it? And it's important that the codes runs when the user is not in the app but did not close it with the task manager.

(Sorry for the formatting)

MainActivity:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

        private final String tag = "MainActivity";

        private TimePicker timePicker;
        private Button button;

        private boolean isRunning;
        private PendingIntent servicePI;
        private AlarmManager alarmManager;

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

        @Override
        public void onClick(View v) {
            if (isRunning) {
                Log.d(tag, "Stop service");

                alarmManager.cancel(servicePI);
                setState(false);
            }else {
                Log.d(tag, "Start service");

                int[] alarmTime = new int[2];
                if (Build.VERSION.SDK_INT < 23) {
                    alarmTime[0] = timePicker.getCurrentHour();
                    alarmTime[1] = timePicker.getCurrentMinute();
                }else {
                    alarmTime[0] = timePicker.getHour();
                    alarmTime[1] = timePicker.getMinute();
                }

                Calendar c = Calendar.getInstance();
                c.set(Calendar.HOUR_OF_DAY, alarmTime[0]);
                c.set(Calendar.MINUTE, alarmTime[1]);
                c.set(Calendar.SECOND, 0);

                alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), servicePI);
                setState(true);
            }
        }

        private void setState(boolean state) {
            isRunning = state;
            if (state)
                button.setText("Stop");
            else
                button.setText("Start");
        }

        private void init() {
            timePicker = findViewById(R.id.timePicker);
            button = findViewById(R.id.button_power);
            button.setOnClickListener(this);

            setState(false);

            Intent service = new Intent(getApplicationContext(), MyService.class);
            servicePI = PendingIntent.getService(getApplication(), 0, service,0);
            alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        }
    }


MyService:
public class MyService extends Service {

            private final String tag = "MyService";

            @Override
            public int onStartCommand(Intent intent, int flags, int startId) {
                Log.d(tag, "Start");
                return super.onStartCommand(intent, flags, startId);
            }

            @Override
            public IBinder onBind(Intent intent) {
                return null;
            }
    }

Solution

  • Calls to AlarmManager.set() are inexact. This allows Android to optimize the power usage of the device. If you require exact delivery, you need to use setExact() or setExactAndAllowWhileIdle(). See the NOTE in the documentation.