Android 服务 setInexactRepeating asyncTask 问题与 SharedPreferences

Android service setInexactRepeating asyncTask issue with SharedPreferences

我的学生应用程序在后台服务中下载分数并检查是否有比上次更多的分数。如果有任何新标记,它会推送通知并重写 sharedPreferences 中的标记数。它有效,但有时它会同时为同一标记创建 多个 通知。

触发广播接收器的IntentService:

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;
}

广播接收器onReceive方法初始化sharedPreferences属性和numberOfMarksSaved并启动下载数据的AsyncTask:

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 方法检查下载标记数是否大于上次:

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();

正如我所说,这主要是有效的,但有时 BroadcastReceiver 会立即被触发 两次 - 第一个重写 sharedPreferences 中的值,但第二个不会' t "notice" 共享首选项中的值已更改。我怎样才能防止这种情况发生?

编辑: 我什至尝试了 setRepeating 而不是 setInexactRepeating - 没有任何改变(我怀疑 android alarmManager 时移)。这是我的日志:

06-11 18:14:27.732 ... I/Just 即将:下载新数据

06-11 18:14:27.761 ... I/Just 即将:下载新数据

06-11 18:14:27.907 ... I/Saved 和新:89、90

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

06-11 18:14:28.004 ... I/Saved 及新:89、90

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

由于不精确的重复警报的工作方式和长时间的 运行 后台操作,很可能在问题发生时同时有多个 AsyncTask 个实例 运行。

来自 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.

对于如此低的间隔,我建议使用 setRepeating() 而不是 setInexactRepeating()

Service 中保留 AsyncTask 的实例。

然后,你可以这样做:

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

防止您的 AsyncTask 运行 同时出现多个实例。