0

まず、どこにあるのかわからない、理由がわからない、ConcurrentModificationExceptionが発生します。私のLogcatは故障しています(または単に使用できません)が、例外に関する情報は表示されません(私はそれに関する記事をたくさん読んでいて、何も役に立たず、電話を正しくデバッグできない可能性があります)

第二に、私の混乱した英語について申し訳ありませんが、私はできるだけ明確に定式化しようとします、コードは役立つかもしれません、私を助けてください

したがって、問題は次のとおりです。

Mapviewと5つのカスタムCustomItemizedOverlay(ソース番号1)を使用しています。MapViewから、いくつかの(1、2、最大5)スレッドをWebサービス(ソース番号2)に開始し、結果を取得した後(リスト)、それらをmapoverlay(ソース番号3)に描画します。

そのため、MapView(5つのResponseHandlerInterfacesを実装)はmyActions(スレッドを拡張)を介してWebサービスに要求を送信し、アクションが応答を取得すると、responseHandler.reportResponseList(リストリスト)メソッドを呼び出します。(MapViewはここでコントロールを取り戻します)

and all of it causes ConcurrentModificationException sometimes
(rarely ArrayIndexOutOfBoundsException)

必要なリストを設定するためのオプションアクティビティがあり、リストを取得するための更新ボタンもあります。一例をご紹介します。

MapViewを開いたところ、空です。必要なオブジェクトは1種類だけです。更新をタップします。ネットワーク通信後、マップビューにマーカーが表示されます。かっこいい、それは働いています。次に、[オプション]に移動し、要求するオブジェクトをさらに設定します。mapviewでRefreshを再度使用すると、すべての種類のオブジェクトが取得される場合と、ConcurrentModificationExceptionが発生する場合があります。

ソースNo.1

public class CustomItemizedOverlay<T> extends ItemizedOverlay<T>{

private Context mContext;
private Object lock = new Object();
private CopyOnWriteArrayList<T> overlays = new CopyOnWriteArrayList<T>();

public CustomItemizedOverlay(Drawable marker, Context context) {
    super(boundCenterBottom(marker));
    this.mContext = context;
    populate();
}
@Override
protected boolean onTap(int index){
 // doesn't matter
}
public void clear(){
    synchronized (lock) {
        overlays.clear();
    }
}
public void addOverlay(T overlay){
    synchronized (lock) {
        overlays.add(overlay);
        setLastFocusedIndex(-1);
        populate();
    }
}
public void removeOverlay(int selected){
    synchronized (lock) {
        overlays.remove(selected);
        populate();
        setLastFocusedIndex(-1);
    }
}
@Override
protected T createItem(int i) {
    synchronized (lock) {
        return overlays.get(i);         
    }
}
@Override
public int size() {
    synchronized (lock) {
        return overlays.size();
    }
}
public void setLock(Object o){
        this.lock = o;
    }
}

ソースNo.2

MapView:

public class MyMap extends MapActivity implements LocationListener, RestResPonseHandler { // there are 5 type of responsehandlers, one for each overlay 

private MapView mapView;
private MyLocationOverlay myLocationOverlay;

private Object lock = new Object();

private CustomItemizedOverlay<CustomOverlayItem<MyObject1>> my1Overlay;
private CustomItemizedOverlay<CustomOverlayItem<MyObject2>> my2Overlay;
private CustomItemizedOverlay<CustomOverlayItem<MyObject3>> my3Overlay;
private CustomItemizedOverlay<CustomOverlayItem<MyObject4>> my4Overlay;
private CustomItemizedOverlay<CustomOverlayItem<MyObject5>> my5Overlay;

public void getObject1List(){ // there are 5 getList methods
    new RestAction(this).start(); // 'this' is the object which implements required RestResponseHandler interface. in every case it will be 'this'. MyMap implements all kind of required RestResponseHandler interfaces
    }

ソースNo.3(非メインスレッド)//これは各「CustomItemizedOverlayfillingmethod」のパターンです。アクションが結果(オブジェクトのリスト)を報告した後、mapviewは実際のオーバーレイをOverlayItemsで埋めます

@Override
public void reportResponseList(List<MyObject1> objects) {
    if (my1Overlay == null){
        List<Overlay> mapOverlays = mapView.getOverlays();
        Drawable marker = this.getResources().getDrawable(R.drawable.icon);
        my1Overlay = new CustomItemizedOverlay<CustomOverlayItem<MyObject1>>(marker, this);
        my1Overlay.setLock(lock); // MyMap has lock object, look at source 2 (also CustomItemizedOverlay (source 1) )
        mapOverlays.add(my1Overlay);
    } else {
        my1Overlay.clear(); 
    }   
    synchronized (lock) {
        for(int i=0;i<objects.size();++i){
            MyObject1 object = objects.get(i);
            CustomOverlayItem<MyObject1> item = new CustomOverlayItem<CustomBuilding>(object.getPositionId(), object);
            my1Overlay.addOverlay(item);
        }
    refreshView();
    }
}

refreshViewがmapViewを更新するためにメインスレッドに実行可能な投稿を行う場所。

public void refreshView(){
    new Thread(new Runnable(){
        @Override
        public void run(){
            mapView.post(new Runnable(){
                @Override
                public void run(){
                    mapView.invalidate();
                }
            }); 
        }
    }).start();
}

解決策:CommonsWareの回答の後、ソースを次のように変更しました:

@Override
public void reportResponseList(final List<MyObject1> objects) {     
    if (my1Overlay == null){
        List<Overlay> mapOverlays = mapView.getOverlays();
        Drawable marker = this.getResources().getDrawable(R.drawable.icon);
        my1Overlay = new CustomItemizedOverlay<CustomOverlayItem<MyObject1>>(marker, this);
        my1Overlay.setLock(lock);
        mapOverlays.add(my1Overlay);
    } else {
        runOnUiThread(new Runnable(){
            @Override
            public void run(){
                my1Overlay.clear();
            }
        }); 
    }
    runOnUiThread(new Runnable(){
        @Override
        public void run(){
            for(int i=0;i<objects.size();++i){
                MyObject1 object = objects.get(i);
                CustomOverlayItem<MyObject1> item = new CustomOverlayItem<MyObject1>(object.getPositionId(), object);
                my1Overlay.addOverlay(item);
            }
            refreshView();  
        }
    });
}

そして今、それはうまくいくようです。どれだけきれいかわかりませんが、うまくいくようです。(多分mapOverlays.add()メソッドもメインスレッドにあるはずです)どうもありがとうございました。

4

1 に答える 1

0

が呼び出されるまでにmy1Overlayすでにの一部である場合は、バックグラウンドスレッドで変更しないでください。それを使用します。代わりに、バックグラウンドスレッドで新しいものを作成し、メインアプリケーションスレッドでスワップオーバーレイ(古いものを削除し、新しいものを追加します)を作成します。MapViewreportResponseList()MapViewOverlayOverlay

于 2012-04-30T13:20:22.157 に答える