在我的应用程序中,我有一个不断涌入的数据和一个在X时间过后触发的调度程序,比方说20秒。触发时,会运行一个函数,将当前批量数据发送到API,如果网络连接可用,或将其保存在应用程序的Room数据库中。
所以我的问题出现在以下情况中。假设我有应用程序打开收集数据1小时但没有互联网连接。应用程序应该将所有这180个20秒的捆绑包保存在数据库中,这样做没有问题,每次调度程序触发时都会保存每个捆绑包。
现在说我决定打开我的WiFi并重新建立连接。这意味着从现在开始,所有20秒的捆绑包都应该上传到服务器,并且已经存储在数据库中的所有捆绑包都应排队等候发送到服务器。
以下代码块包含调度程序每20秒调用一次的函数。如果没有互联网,则toCache
标志为真,并且应该在房间中保存数据。
ExecutorService exec = Executors.newSingleThreadExecutor();
exec.execute(() -> {
fromDb = (ArrayList<DataModel>) dataDB.userDAO().getData();
if (fromDb.size() != 0)
hasCachedData = true;
if (toCache) {
dataDB.userDAO().insertData(new DataModel(req));
} else {
synchronized (this) {
if (hasCachedData) {
//Begin uploading data from the database
hasCachedData = false;
ArrayList<Observable<?>> requests = new ArrayList<>();
for (DataModel d : fromDb) {
requests.add(api.sendDeviceDataObs(new DataRequestModel(d)).onErrorReturn(throwable -> null));
}
Observable.zip(
requests,
objects -> {
// Objects[] is an array of combined results of completed requests
// do something with those results and emit new event
for (int i = 0; i < objects.length; i++) {
if ((objects[i]) != null) {
toRemove.add(fromDb.get(i));
}
}
return new Object();
})
// After all requests had been performed the next observer will receive the Object, returned from Function
.subscribe(
// Will be triggered if all requests will end successfully (4xx and 5xx also are successful requests too)
o -> {
dataDB.userDAO().deleteData(toRemove.toArray(new DataModel[toRemove.size()]));
fromDb.removeAll(toRemove);
toRemove.clear();
if (fromDb.size() != 0) {
hasCachedData = true;
}
Log.d("lol", o.toString());
//Do something on successful completion of all requests
}, e -> {
toRemove.clear();
hasCachedData = true;
Log.d("error", e.toString());
}
);
}
}
// Send current data to server with Retrofit
api.sendDeviceData(req).enqueue(new Callback<ResponseBody>() { ... }
我面临的问题是我得到重复的数据。我相信,当重新建立连接后会发出很多请求,并且当下一个20秒触发器触发时,会发生从数据库中检索和上传数据的代码再次运行。
这有更好的实施吗?我错过了什么吗?另外,Observables.zip()有效,但我无法检查每个响应是否为200OK,这不是错误处理的理想选择。
提前致谢。