我的学生申请在后台服务中下载标记,并检查是否有比上次更多的分数。如果有任何新标记,则会推送通知并重写 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();
正如我所说,这主要是有效的,但有时会立即触发连续两次触发 - 第一个重写sharedPreferences中的值,但第二个没有“注意到”共享首选项中的值已更改。我该如何防止这种情况?
修改 我试过甚至setRepeating而不是setInexactRepeating - 没有改变(我怀疑android alarmManager时移)。这是我的日志:
06-11 18:14:27.732 ...我/即将:下载新数据
06-11 18:14:27.761 ...我/即将:下载新数据
06-11 18:14:27.907 ...我/保存&新:89,90
06-11 18:14:27.933 ...我/通知已烘焙 - 身份证号码:1077819997
06-11 18:14:28.004 ...我/保存&新:89,90
06-11 18:14:28.006 ...我/通知烘焙 - 身份证号码:1077820069
答案 0 :(得分:1)
由于重复警报的不精确运行以及长时间运行的后台操作,很可能在问题发生时同时运行多个x
个实例。
来自AsyncTask
的文档:
您的闹钟首次触发不会在请求的时间之前,但是 在此之后几乎整整一段时间内可能不会发生。在 另外,重复报警的整个周期将为 要求,任何两次连续发出警报之间的时间 可能会有所不同。
对于如此短的间隔,我建议使用AlarmManager
代替setRepeating()
和强>
在setInexactRepeating()
中保留AsyncTask
的实例。
然后,你可以这样做:
Service
防止if(task.getStatus == AsyncTask.Status.FINISHED) {
task = new DownloadDataTask();
task.execute(context.getString(R.string.LOGIN_PAGE_URL), username, password);
}
的多个实例同时运行。