首先,我不知道在哪裏,我不知道爲什麼,我得到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()方法也應該在主線程上)非常感謝。
so my1Overlay.clear()和synchronized循環是否必須在主線程上運行? – Victor
@Victor:這是另一種可能性,儘管如果每個人都在主應用程序線程上訪問它,那麼你不再需要它被「同步」。 – CommonsWare
和可以mapOverlays.add(my1Overlay);在非主線程? – Victor