シナリオ
ステップ 1: Location Manager を初期化して、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に更新できます。この場合、スレッド 2 は processing=false 行のみを取得します。これは解決策ですか?他の推奨事項はありますか?Thread1が処理を更新している間、Thread2がデータを取得するためにわずかな変更があると私はまだ信じています...ありがとう。
後で編集:このアプローチを試した余分な考えとアイデア
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時間接続できないとどうなりますか?読み取られた場所ごとに、新しいスレッドが追加されます...しかし、このスレッドはどのくらい続きますか? ユーザーが非常に高速で運転している場合、1 ~ 2 秒ごとに場所を読み取ることができた場合、このメカニズムは Web アクセスをキューに保持し、スレッドが次々と発生するのではないかと心配しています。
別の順序で考えると、サービスの onCreate メソッドで新しいスレッドを作成するとどうなるでしょうか。何かのようなもの:
@Override
public void onCreate() {
new Thread(new Runnable() {
@Override
public void run() {
startLocationListener();
}
}).start();
}
そして startLocationListener() で GPS 位置情報の読み取りを開始します。onLocationChanged はこのスレッドで実行され、UI スレッドに干渉しませんか?
独自のスレッドで実行される Service を使用する方が賢明でしょうか? スレッドについて心配する必要はありませんか?
現在のアプローチを使用すると、アプリは仕事をしますが、ランダムに何か問題が発生し、理由を理解できません。アクティビティの 1 つがサービスにバインドして更新を受け取ります。アプリが 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();
}