场景
第 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数据库是否有发送失败的记录
- 如果有,请将它们与当前位置一起发送到网络服务
- 如果没有,则仅发送当前位置
- 如果发送失败(主要是由于数据连接),请在数据库中插入位置以供将来读取
- 如果发送成功,则从数据库中删除所有行
问题
所有这些都是在服务的后台完成的。对于每个 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();
}
根据我读到的内容,这个线程池应该强制线程一个接一个地执行,对吗? (即使我确实有一种感觉,我误解了它的目的)如果是这样,如果我一个小时没有连接会发生什么?对于读取的每个位置,都会添加一个新线程...但是该线程持续多长时间?我担心如果用户驾驶速度非常快会发生什么,我可以每 1-2 秒读取一次位置,这种机制是否会将我的 Web 访问保留在队列中,一个线程接一个线程?
换个思路,如果我在服务的 onCreate 方法中创建一个新线程会怎样。像这样的东西:
@Override
public void onCreate() {
new Thread(new Runnable() {
@Override
public void run() {
startLocationListener();
}
}).start();
}
在 startLocationListener() 中我开始读取 GPS 位置。 onLocationChanged 会在此线程上执行并且不会干扰我的 UI 线程吗?
使用在自己的线程中运行的服务会更明智吗?所以我不必担心线程?
使用当前的方法,应用程序可以完成工作,但出现了一些错误,随机发生,并且无法找出原因:我的一项 Activity 绑定(bind)到服务以接收更新,当应用程序获取更新时,我小心地取消绑定(bind)它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();
}
最佳答案
所以让我说清楚:您想从后台线程一个接一个地发送位置。实现此目的的一个简单方案是(类似于您编辑的代码,但我没有看到 ScheduledExecutor
的原因):
private ExecutorService exec;
@Override
public void onCreate() {
exec = Executors.newSingleThreadExecutor();
}
@Override
public void onLocationChanged(Location location) {
exec.submit(new Runnable() {
@Override
public void run() {
sendLocation(location);
}
});
}
@Override
public void onDestroy() {
exec.shutdownNow();
}
这在幕后所做的基本上是创建一个后台线程和一个任务队列。每次读取一个位置时,都会将一个新任务放入队列中。线程不断轮询队列并按顺序执行任务。
关于android - 在 Android 中长期运行的服务上读取、存储和发送读取的 GPS 位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12044952/