1

断続的な ConcurrentModificationException の原因となるエラーを修正しようとしています。何が起こっているのかというと、大量のジオポイントが ItemizedOverlay で表示されているということです。ただし、マップを移動すると、現在のすべてのオーバーレイ アイテム (ジオポイント) を消去して、新しいビュー ウィンドウに適した新しいポイントに置き換えようとしています。

したがって、古いオーバーレイをクリアして新しいオーバーレイに置き換えるコールバック関数があります。私のバグは、これを同時に実行しようとする複数のスレッドに起因すると思います。関連するセクションを以下に示します。オーバーレイなどが低レベルでどのように機能するかについての理解は非常に限られているため、これが問題を引き起こしている可能性があることを誰かが確認 (または反論) できるかどうか疑問に思っていました.

//first clear out the old overlays
List<Overlay> mapOverlays = mapView.getOverlays();
mapOverlays.clear();

//create the new overlays, each initialized with appropriate Drawables
MenuOverlay lowOverlay = new MenuOverlay(this, lowRisk);//(all valid Drawables)
MenuOverlay medOverlay = new MenuOverlay(this, medRisk);
MenuOverlay highOverlay = new MenuOverlay(this, highRisk);

//populate the overlays

//add the new overlays into the list of overlays
mapOverlays.add(lowOverlay);
mapOverlays.add(medOverlay);
mapOverlays.add(highOverlay);

//make the map refresh; this operation has to be pushed to another thread
Runnable runnable = new Runnable() {
    public void run() {
        mapView.invalidate();
    }
};
runOnUiThread(runnable);

このメソッドを作成しようとしましsynchronizedたが、それでもエラーが発生しました。これは、前のランナブルが終了する前に、新しいランナブルが UI スレッドにプッシュされたために発生する可能性がありますか? populate は invalidate よりも優れた方法であるという言及を見てきましたが、それらがどのように異なるのか完全にはわかりません。これを解決する方法はありますか?

4

1 に答える 1

1

オーバーレイのセットの変更は、常に UI スレッドで行う必要があります。Listが返すはgetOverlays()によって所有されておりMapView、いつでもリストを表示または操作することができます。

多くのジオポイントを操作しているため、バックグラウンド スレッドがオーバーレイをクリア (または追加) している一方MapViewで、UI スレッドでそれらを反復処理している可能性があります。ConcurrentModificationException基礎となるオーバーレイのセットが変更されるとイテレータが無効になるため、これは a をトリガーします。変更が UI スレッドにすぐに表示されない場合があるため、クラッシュは断続的です。

オーバーレイの設定は、通常、このタイプのワークフローの遅い部分です。clear()同時変更を回避するには、バックグラウンド スレッドでオーバーレイを設定しadd()Runnable. (別のオプションは、を使用することAsyncTaskです。)

例えば:

// Slow setup steps
final MenuOverlay lowOverlay = new MenuOverlay(this, lowRisk);
final MenuOverlay medOverlay = new MenuOverlay(this, medRisk);
final MenuOverlay highOverlay = new MenuOverlay(this, highRisk);

Runnable runnable = new Runnable() {
    public void run() {
        // Anything that touches UI widgets (map, overlay set, views, etc.)
        List<Overlay> mapOverlays = mapView.getOverlays();
        mapOverlays.clear();

        mapOverlays.add(lowOverlay);
        mapOverlays.add(medOverlay);
        mapOverlays.add(highOverlay);

        mapView.invalidate();
    }
};

runOnUiThread(runnable);
于 2013-01-24T01:00:47.317 に答える