まず、どこにあるのかわからない、理由がわからない、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()メソッドもメインスレッドにあるはずです)どうもありがとうございました。