Java 从修改覆盖解决ConcurrentModificationException

Java 从修改覆盖解决ConcurrentModificationException,java,android,debugging,concurrency,Java,Android,Debugging,Concurrency,我一直在试图修复导致间歇ConcurrentModificationException的错误。发生的事情是,我有一个ItemizedOverlay显示的地质点吨。但是,当移动地图时,我会尝试清除所有当前的覆盖项目(地质点),并用适合新视图窗口的新点替换它们 因此,我有一个回调函数,它清除旧的覆盖并用新的覆盖替换它们。我认为我的错误源于多个线程试图同时执行此操作。相关章节如下。我对覆盖层和这类内容如何在低水平上工作的理解非常有限,因此我想知道是否有人能够证实(或反驳)这可能会导致问题 //firs

我一直在试图修复导致间歇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);
//首先清除旧覆盖层
List mapOverlays=mapView.getOverlays();
mapOverlays.clear();
//创建新的覆盖层,每个覆盖层都使用适当的可绘制图形进行初始化
MenuOverlay lowOverlay=新MenuOverlay(这是低风险)//(所有有效提款权)
MenuOverlay medOverlay=新MenuOverlay(这是medRisk);
MenuOverlay highOverlay=新MenuOverlay(这是高风险);
//填充覆盖层
//将新覆盖添加到覆盖列表中
添加(低覆盖);
mapOverlays.add(medOverlay);
添加(高覆盖);
//使地图刷新;必须将此操作推送到另一个线程
Runnable Runnable=新的Runnable(){
公开募捐{
mapView.invalidate();
}
};
runOnUiThread(可运行);

我尝试使此方法同步,但仍然出现错误。这可能是因为在前一个runnable终止之前,新的runnable被推送到UI线程吗?我看到有人提到,填充是一种比无效更好的方法,尽管我不完全确定它们有什么不同。有没有办法解决这个问题?

修改覆盖集应该始终在UI线程上完成。
getOverlays()
返回的
列表
MapView
所有,它可以随时决定查看或操作列表

由于您使用的是大量地质点,因此当
MapView
在UI线程上迭代覆盖时,您的后台线程可能正在清除(或添加)覆盖。这将触发一个
ConcurrentModificationException
,因为迭代器在其基础覆盖集更改时无效。有时,UI线程无法立即看到更改,因此崩溃是间歇性的

设置覆盖通常是此类工作流中缓慢的一部分。为了避免并发修改,您可以在后台线程中设置覆盖,然后在
Runnable
内部调用
clear()
add()
。(另一个选项是使用
异步任务

例如:

// 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);
//设置步骤缓慢
最终菜单Overlay lowOverlay=新菜单Overlay(此为低风险);
最终MenuOverlay medOverlay=新MenuOverlay(这是medRisk);
最终菜单Overlay highOverlay=新菜单Overlay(这是高风险);
Runnable Runnable=新的Runnable(){
公开募捐{
//任何涉及UI小部件(地图、覆盖集、视图等)的内容
List mapOverlays=mapView.getOverlays();
mapOverlays.clear();
添加(低覆盖);
mapOverlays.add(medOverlay);
添加(高覆盖);
mapView.invalidate();
}
};
runOnUiThread(可运行);

修改覆盖集应始终在UI线程上完成。
getOverlays()
返回的
列表
MapView
所有,它可以随时决定查看或操作列表

由于您使用的是大量地质点,因此当
MapView
在UI线程上迭代覆盖时,您的后台线程可能正在清除(或添加)覆盖。这将触发一个
ConcurrentModificationException
,因为迭代器在其基础覆盖集更改时无效。有时,UI线程无法立即看到更改,因此崩溃是间歇性的

设置覆盖通常是此类工作流中缓慢的一部分。为了避免并发修改,您可以在后台线程中设置覆盖,然后在
Runnable
内部调用
clear()
add()
。(另一个选项是使用
异步任务

例如:

// 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);
//设置步骤缓慢
最终菜单Overlay lowOverlay=新菜单Overlay(此为低风险);
最终MenuOverlay medOverlay=新MenuOverlay(这是medRisk);
最终菜单Overlay highOverlay=新菜单Overlay(这是高风险);
Runnable Runnable=新的Runnable(){
公开募捐{
//任何涉及UI小部件(地图、覆盖集、视图等)的内容
List mapOverlays=mapView.getOverlays();
mapOverlays.clear();
添加(低覆盖);
mapOverlays.add(medOverlay);
添加(高覆盖);
mapView.invalidate();
}
};
runOnUiThread(可运行);