2

シナリオ

ステップ 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();
    }
4

2 に答える 2

1

sendLocation 呼び出しごとに、新しいスレッドを作成します。

なんで?

しかし、送信が失敗し、ユーザーが運転している場合、場所の読み取りが非常に頻繁に発生し、2 ~ 3 個のスレッドがすべて同じ未送信の場所を送信しようとしている可能性が高くなります。

これが私が「なぜ?」と尋ねた理由です。その上。

Thread1 がリストを受信して​​送信しようとした場合、Thread2 と Thread3 はそれを読み取って送信しようとすることはできません。Thread1 はリストを正常に送信できる可能性があるからです。どうすればこれを防ぐことができますか? Thread2 がリストを読み取らないようにするにはどうすればよいですか?

私見、そもそも Thread2 と Thread3 を持たないことで。一度に 1 つのスレッドを使用して、未送信のデータをすべて送信します。これはおそらく長命のスレッドであり、ワーク キューで動作します (以前に更新に失敗し、他に更新がない場合は、X 時間後に再試行することを確認したい場合を処理するためのある種のタイマー メカニズムと組み合わされています)。イベントにより、それよりも早く試す必要がありました)。目的を達成するためにそれ以上のものが必要な理由がわかりません。

于 2012-08-20T20:58:07.200 に答える
1

つまり、バックグラウンド スレッドから次々と位置情報を送信したいとします。これを達成するための簡単なスキームは次のようになります(編集したコードに似ていますが、理由はわかりません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();
}

これが内部で行うことは、基本的にはバックグラウンド スレッドとタスクのキューを作成することです。ロケーションが読み取られるたびに、新しいタスクがキューに入れられます。スレッドはキューを継続的にポーリングし、タスクを順番に実行します。

于 2012-09-04T07:40:45.757 に答える