1

I'm building an Android pedometer app that sends data to a SQLite database at 30 minute intervals using AlarmManager; if the phone is off when the transfer is supposed to occur, it will do the transfer immediately when the phone is switched back on.

(30 minutes is for testing - the actual interval will be 1 week).

I was told alarms wouldn't persist unless I used "intent.action.BOOT_COMPLETED" in the manifest, so I put that as a filter for my Alarm.java class.

My code to set the alarm (in MainActivity.java) is as follows:

public void insertData(View view) {
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    long time= System.currentTimeMillis();
    Date d = new Date(time);
    editor.putLong("alarmtime", time); //the next ring time for the alarm is put in SharedPreferences
    editor.apply();

    Intent intent = new Intent(this, Alarm.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
            this,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager.setRepeating(AlarmManager.RTC, time, AlarmManager.INTERVAL_DAY, pendingIntent);
    Toast.makeText(MainActivity.this, "Alarm Set", Toast.LENGTH_LONG).show();
}

The code in the Alarm.java class (which extends BroadcastReceiver) is as follows:

Context context; //plus other declared variables

@Override
public void onReceive(Context context, Intent intent) {
    this.context = context;
    preferences = context.getSharedPreferences("MyPreferences", context.MODE_PRIVATE);
    editor = preferences.edit();
    long startedtime = preferences.getLong("alarmtime", 0); //get the next ring time
    Date nextRingTime = new Date(startedtime);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    String action = intent.getAction();
    //sometimes the onReceive() is called by the phone turning on
    if (action != null && action.equals(Intent.ACTION_BOOT_COMPLETED)) {

        //if phone turned on again before the alarm, just re-create the alarm for the same time, don't transfer data
        Date currenttime = new Date(System.currentTimeMillis());
        if ((currenttime.compareTo(nextRingTime) < 0)) {  
            Intent newintent = new Intent(context, Alarm.class);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    context,
                    0,
                    newintent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            alarmManager.setRepeating(AlarmManager.RTC, startedtime, AlarmManager.INTERVAL_HALF_HOUR, pendingIntent);
            return;
        }

        else if ((currenttime.compareTo(nextRingTime) > 0)) {
        //if the phone was off when the alarm was supposed to make the transfer, set the alarm to the next intended ring time and insert data to db immediately

            Calendar d = Calendar.getInstance();
            d.setTime(nextRingTime);
            d.add(Calendar.MINUTE, 30);
            long newtime = d.getTimeInMillis();
            Intent newintent = new Intent(context, Alarm.class);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    context,
                    0,
                    newintent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            alarmManager.setRepeating(AlarmManager.RTC, newtime, AlarmManager.INTERVAL_HALF_HOUR, pendingIntent);
        }
    }
    myDb = new DatabaseHelper(context);
    // code for inserting data into database

    //finally, update next intended ring time in SharedPreferences now that this particular transfer is done:
    Calendar c = Calendar.getInstance();
    c.setTime(nextRingTime);
    c.add(Calendar.MINUTE, 30);
    Log.v("insertdone, alarrm now", c.getTime().toString());
    long nexttime = c.getTimeInMillis();
    editor.putLong("alarmtime", nextime);
    editor.apply();
}

Unfortunately, if the phone is off at the time of a scheduled alarm, when I turn it on afterwards, it calls onReceive() TWICE, meaning it inserts data twice.

How can this be stopped?

A solution would maybe be to use RTC_WAKEUP, but I really don't want to do that unless as an absolute last resort.

N.B. I have a separate bootBroadcastReceiver class that uses "intent.action.BOOT_COMPLETED" to restart a pedometer service, and am wondering whether having 2 different things started by the boot is causing problems...

AM128
  • 61
  • 5

0 Answers0