首先,我不知道在哪里,我不知道为什么,我得到了 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() 方法也应该在主线程上)非常感谢。