0

首先,我不知道在哪里,我不知道为什么,我得到了 ConcurrentModificationException。我的 Logcat 出现故障(或者只是我无法使用它),但从未显示任何有关异常的信息(我阅读了很多关于它的文章,但没有任何帮助,可能无法正确调试我的手机)

其次对不起我的英语混乱,我尽量清楚地表达,代码可以帮助,请帮助我

所以,问题是下一个:

我在上面使用 Mapview 和 5 个自定义 CustomItemizedOverlay(源编号 1)。从 MapView 我开始一些(1、2、最大 5)线程到 web 服务(源号 2),在我得到结果后(它是列表)我将它们绘制到 mapoverlay 中(源号 3)

所以 MapView (实现 5 个 ResponseHandlerInterfaces )通过 myActions (扩展线程)向 webservice 发送请求,当动作得到响应时,它们调用 responseHandler.reportResponseList(List list) 方法。(MapView 在这里取回控制权)

and all of it causes ConcurrentModificationException sometimes
(rarely ArrayIndexOutOfBoundsException)

我有选项活动来设置所需的列表,我也有刷新按钮来获取列表。让我带你看一个例子。

我刚打开 MapView,它是空的。我只需要一种对象。我点击刷新,网络通信后,我在我的地图视图上得到标记。酷,它的工作。现在我要去选项,我设置更多的对象来请求。在 mapview 再次使用 Refresh,有时我得到各种对象,有时我得到 ConcurrentModificationException。

源头 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;
    }
}

源 2 号

地图视图:

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
    }

源号 3(非主线程)//这是每个“CustomItemizedOverlay 填充方法”的模式。动作报告结果(对象列表)后,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 回答