设想
第 1 步:初始化位置管理器以每 50 米读取一次 GPS 位置:
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 50, locationListenerGps);
第 2 步:每次读取位置时:
@Override
public void onLocationChanged(Location location) {
new Thread(new Runnable() {
@Override
public void run() {
sendLocation(location);
}
}).start();
}
第 3 步:在 sendLocation 上,我做了几件事:
- 查询本地sqlite数据库发送失败记录
- 如果有,将它们与当前位置一起发送到 Web 服务
- 如果没有,只发送当前位置
- 如果发送失败(主要是因为数据连接),则在数据库中插入位置以供将来读取
- 如果发送成功,则从数据库中删除所有行
问题
所有这些都是在服务的后台完成的。对于每个 sendLocation 调用,我都会创建一个新线程。虽然连接正常,但一切正常。但是,当发送失败并且用户正在开车时,位置读取会经常发生,并且很有可能有 2-3 个线程都试图发送相同的未发送位置。如果 Thread1 收到列表并尝试发送它,Thread2 和 Thread3 应该无法读取它并尝试发送它,因为 Thread1 可能会成功发送它。我怎样才能防止这种情况发生?如何确保 Thread2 不读取列表?
从我现在的想法来看,我可以在“处理”表中添加一个新字段,并且对于检索到的所有发送行,将该字段更新为 true。在这种情况下,Thread2 只会得到 processing=false 行。这是一个解决方案吗?还有其他建议吗?我仍然认为 Thread2 获取数据有细微的变化,而 Thread1 正在更新处理...谢谢。
稍后编辑:我尝试过这种方法的额外想法和想法
private ExecutorService threadPool;
@Override
public void onCreate() {
scheduleTaskExecutor = Executors.newSingleThreadScheduledExecutor();
threadPool = Executors.newSingleThreadExecutor();
//also need to send location every 60 seconds if no other location was read
scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
sendLocation(lastLocation);
}
}, 60, 60, TimeUnit.SECONDS);
}
@Override
public void onLocationChanged(Location location) {
threadPool.execute(new Runnable() {
@Override
public void run() {
sendLocation(location);
}
});
}
@Override
public void onDestroy() {
threadPool.shutdownNow();
}
根据我的阅读,这个 threadPool 应该强制线程一个接一个地执行,对吧?(即使我确实感觉我误解了它的目的)如果是这样,如果我一个小时没有连接会发生什么?对于读取的每个位置,都会添加一个新线程......但是这个线程持续多长时间?我担心如果用户开得非常快会发生什么,我可以每 1-2 秒读取一次位置,这种机制是否会将我的 Web 访问保持在一个队列中,一个线程接一个线程?
在另一个想法中,如果我创建一个新线程的服务的 onCreate 方法会怎样。就像是:
@Override
public void onCreate() {
new Thread(new Runnable() {
@Override
public void run() {
startLocationListener();
}
}).start();
}
在 startLocationListener() 中,我开始读取 GPS 位置。onLocationChanged 会在这个线程上执行并且不会干扰我的 UI 线程吗?
使用在自己的线程中运行的服务会更明智吗?所以我不必担心线程?
使用当前的方法,应用程序完成了工作,但是随机发生了一些错误并且无法找出原因:我的一个活动绑定到服务以接收更新,当应用程序启动时我小心地取消绑定它 onPause.. . 但有时服务会继续运行,因为我可以看到它的通知图标显示。我将对此进行更多调查,但我需要确定一种强大/可靠的方式来处理位置读取和发送。
稍后稍后编辑
这种方法怎么样:
private ExecutorService scheduleTaskExecutor;
@Override
public void onCreate() {
scheduleTaskExecutor = Executors.newSingleThreadScheduledExecutor();
//also need to send location every 60 seconds if no other location was read
scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
sendLocation(lastLocation);
}
}, 60, 60, TimeUnit.SECONDS);
}
@Override
public void onLocationChanged(Location location) {
scheduleTaskExecutor.submit(new Runnable() {
@Override
public void run() {
sendLocation(location);
}
});
}
@Override
public void onDestroy() {
scheduleTaskExecutor.shutdownNow();
}