2012-04-30 35 views
0

首先,我不知道在哪裏,我不知道爲什麼,我得到ConcurrentModificationException。我logcat的失靈(或只是我不能用它),但從來沒有顯示有關異常的任何信息(我讀了很多文章關於它的,並沒有什麼幫助,也許不能正確地調試我的手機)Android API 7(2.1),MapView,MultiThreading,ConcurrentModificationException

其次我的困惑英語對不起,我嘗試儘可能清楚我可以制定,代碼可以幫助,請幫我

那麼,問題是下一個:

我使用的MapView和5個自定義CustomItemizedOverlay(來源沒有1)就可以了。 從MapView我開始一些(1,2,最多5)線程到webservice(源2號)和我得到的結果回來(這是列表)我把他們繪製成mapoverlay(源3號)

so MapView (實現5個ResponseHandlerInterfaces)通過myActions(extends Thread)向webservice發送請求,當動作獲得響應時,它們調用responseHandler.reportResponseList(List list)方法。 (MapView取回控制權在這裏)

and all of it causes ConcurrentModificationException sometimes 
(rarely ArrayIndexOutOfBoundsException) 

我有選項活動來設置所需的列表,我也得到刷新按鈕,以獲取列表。讓我帶領你通過一個例子。

我剛剛打開MapView,它是空的。我只需要1種物體。我點擊刷新,網絡通信後,我得到我的地圖視圖上的標記。很酷,它的工作。現在我要去選項,並設置更多的對象來請求。在mapview中再次使用刷新,有時我會得到各種對象,有時我會得到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

如果在調用reportResponseList()my1Overlay已經是MapView的一部分,則不應該在後臺線程上修改它。 MapView將使用Overlay。相反,在後臺線程中創建一個新的Overlay,主應用程序線程上的交換疊加層(刪除舊的,添加新的)。

+0

so my1Overlay.clear()和synchronized循環是否必須在主線程上運行? – Victor

+0

@Victor:這是另一種可能性,儘管如果每個人都在主應用程序線程上訪問它,那麼你不再需要它被「同步」。 – CommonsWare

+0

和可以mapOverlays.add(my1Overlay);在非主線程? – Victor

相關問題