cuddlecheek cuddlecheek - 5 months ago 62
Android Question

Android service setInexactRepeating asyncTask issue with SharedPreferences

My application for students downloads marks in a background service and checks if there are more marks than last time. If there are any new marks, it pushes notification and rewrites the number of marks in sharedPreferences. It works, but sometimes it creates multiple notifications for the same mark at the same time.

The IntentService which triggers a broadcast receiver:

public int onStartCommand(Intent intent, int flags, int startId) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), CheckNewMarksReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);

alarmManager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
0,
2500, alarmIntent);

return START_STICKY;
}


The broadcast receiver onReceive method initializes sharedPreferences attribute and numberOfMarksSaved and starts AsyncTask that downloads data:

DownloadDataTask task = new DownloadDataTask();
task.execute(context.getString(R.string.LOGIN_PAGE_URL), username, password);

dataPreferences = context.getApplicationContext().getSharedPreferences(context.getString(R.string.SHARED_PREFERENCES), Context.MODE_PRIVATE);
numberOfMarksSaved = dataPreferences.getInt(context.getString(R.string.PREFERENCE_NUMBER_OF_MARKS_KEY), -1);


AsyncTasks onPostExecute method checks if the number of downloaded marks is greater than last time:

if (numberOfDownloadedMarks > numberOfMarksSaved) {
...
notifyUserAbout(newMarks, response); // method to fire a notification
}

dataPreferences
.edit()
.putInt(context.getString(R.string.PREFERENCE_NUMBER_OF_MARKS_KEY),
numberOfDownloadedMarks)
.apply();


As I said, this mostly works, but sometimes the BroadcastReceiver is triggered twice in a row immediately - the first one rewrites the value in sharedPreferences, but the second one doesn't "notice" that value in shared preferences was changed. How can I prevent that?

EDIT:
I tried even setRepeating instead of setInexactRepeating - nothing changed (I suspect android alarmManager time shifting). Here is my Log:

06-11 18:14:27.732 ... I/Just about to: download new data

06-11 18:14:27.761 ... I/Just about to: download new data

06-11 18:14:27.907 ... I/Saved & new: 89, 90

06-11 18:14:27.933 ... I/Notification baked - id: 1077819997

06-11 18:14:28.004 ... I/Saved & new: 89, 90

06-11 18:14:28.006 ... I/Notification baked - id: 1077820069

Answer

Because of how inexact repeating alarms work and the long running background operations, most probably there are multiple AsyncTask instances running at the same time when the problem occurs.

From the docs of AlarmManager:

Your alarm's first trigger will not be before the requested time, but it might not occur for almost a full interval after that time. In addition, while the overall period of the repeating alarm will be as requested, the time between any two successive firings of the alarm may vary.

For such low intervals i'd suggest to use setRepeating() instead of setInexactRepeating()

and

keep an instance of your AsyncTask in your Service.

Then, you could do something like this:

if(task.getStatus == AsyncTask.Status.FINISHED) {
    task = new DownloadDataTask();
    task.execute(context.getString(R.string.LOGIN_PAGE_URL), username, password);
}

To prevent multiple instances of your AsyncTask running at the same time.