首先,我不知道在哪里,我不知道为什么,我得到ConcurrentModificationException。我的Logcat乱序(或者我不能使用它)但是从不显示有关异常的任何信息(我阅读了很多关于它的文章,没有任何帮助,也许无法正确调试我的手机)
其次抱歉我的语言很混乱,我尽可能清楚地表达,代码可以提供帮助,请帮帮我
所以,问题是下一个:
我使用Mapview和5个自定义CustomItemizedOverlay(来源编号1)。 从MapView我开始一些(1,2,最多5)线程到webservice(来源2),然后我得到结果(它的列表)我把它们绘制成mapoverlay(来源3)
因此MapView(实现5个ResponseHandlerInterfaces)通过myActions(扩展线程)向webservice发送请求,当动作获得响应时,它们调用responseHandler.reportResponseList(List list)方法。 (MapView在这里取回控件)
and all of it causes ConcurrentModificationException sometimes
(rarely ArrayIndexOutOfBoundsException)
我有选项活动来设置所需的列表,我也有刷新按钮,以获取列表。让我带领你完成一个例子。
我刚打开MapView,它是空的。我只需要一种物体。我点击刷新,在网络通信后,我在我的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
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
}
来源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()方法也应该在主线程上)非常感谢。
答案 0 :(得分:0)
如果在调用my1Overlay
之前MapView
已经是reportResponseList()
的一部分,则不应在后台线程上对其进行修改。 MapView
将使用Overlay
。相反,在后台线程中创建一个新的Overlay
,在主应用程序线程上交换覆盖(删除旧的,添加新的)。