1

這個問題一直在做我的頭,我希望你能幫助!我已經找到了以前的一些問題的答案,希望你的人可以再次工作你的魔法:)ConcurrentModificationException的使用mylocation覆蓋和定時器

好吧,所以我的應用程序的一部分使用谷歌地圖API在地圖上顯示覆蓋(使用自定義覆蓋類)以及使用mylocationoverlay的用戶位置。現在,如果我沒有激活mylocationoverlay,那麼一切正常,但如果激活它,則應用程序組將以ConcurrentModificationException關閉。現在

定時器用於刷新覆蓋其位置在不斷變化。爲此,我使用了一個異步任務來刪除疊加層並添加一個新的位置。我正確地假設mylocationoverlay在背景中做了類似的事情嗎?如果這個假設是有效的,那麼我得出這樣的結論:mylocationoverlay和我的異步任務試圖同時迭代/修改相同的數組。唯一的是,我不知道如何阻止這種情況的發生!

我真的不能在這裏發佈我的代碼作爲其非常大的,但我用從commonsguy創建github上邁出了示例代碼和修改它產生同樣的問題。

任何幫助將不勝感激,因爲這已經真的很令人沮喪的我。提前致謝,並對長篇描述感到抱歉!

編輯:鏈接commonsguy代碼 - https://github.com/commonsguy/cw-advandroid/blob/master/Maps/NooYawkAsync/

編輯2:後添加錯誤跟蹤Java代碼。

package com.commonsware.android.maps; 

import android.graphics.Canvas; 
import android.graphics.drawable.Drawable; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.RelativeLayout; 
import com.google.android.maps.GeoPoint; 
import com.google.android.maps.ItemizedOverlay; 
import com.google.android.maps.MapActivity; 
import com.google.android.maps.MapView; 
import com.google.android.maps.MyLocationOverlay; 
import com.google.android.maps.OverlayItem; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.Timer; 
import java.util.TimerTask; 

public class NooYawk extends MapActivity { 
    private MapView map=null; 
    private MyLocationOverlay me=null; 
    private SitesOverlay sites=null; 
    public Timer timer; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     map=(MapView)findViewById(R.id.map); 

     map.getController().setCenter(getPoint(40.76793169992044, -73.98180484771729)); 
     map.getController().setZoom(17); 
     map.setBuiltInZoomControls(true); 

     me=new MyLocationOverlay(this, map); 
     me.enableMyLocation(); 
     map.getOverlays().add(me); 

     timer = new Timer(); 
     timer.scheduleAtFixedRate(new RemindTask(), 10000, 10000); 

     new OverlayTask().execute(); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     me.enableMyLocation(); 
     me.enableCompass(); 
    }  

    @Override 
    public void onPause() { 
     super.onPause(); 
     me.disableMyLocation(); 
     me.disableCompass(); 
    }  

    @Override 
    protected boolean isRouteDisplayed() { 
     return(false); 
    } 

    private GeoPoint getPoint(double lat, double lon) { 
     return(new GeoPoint((int)(lat*1000000.0), (int)(lon*1000000.0))); 
    } 

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
///////////////////////////////////////////////////////////// TIMER CLASS ////////////////////////////////////////////////////////////// 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

class RemindTask extends TimerTask { 
    public void run() { 
     new OverlayTask().execute(); 
    } 
} 


    private class SitesOverlay extends ItemizedOverlay<CustomItem> { 
     private Drawable heart=null; 
     private List<CustomItem> items=new ArrayList<CustomItem>(); 

     public SitesOverlay() { 
      super(null); 

      heart=getMarker(R.drawable.heart_full); 

      items.add(new CustomItem(getPoint(40.748963847316034, -73.96807193756104), 
               "UN", "United Nations", getMarker(R.drawable.blue_full_marker), heart)); 
      populate(); 
     } 

     @Override 
     protected CustomItem createItem(int i) { 
      return(items.get(i)); 
     } 

     @Override 
     public void draw(Canvas canvas, MapView mapView, boolean shadow) { 
      super.draw(canvas, mapView, shadow); 

     } 

     @Override 
     public int size() { 
      return(items.size()); 
     } 

     void toggleHeart() { 
      CustomItem focus=getFocus(); 

      if (focus!=null) { 
       focus.toggleHeart(); 
      } 

      map.invalidate(); 
     } 

     private Drawable getMarker(int resource) { 
      Drawable marker=getResources().getDrawable(resource); 

      marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight()); 
      boundCenter(marker); 

      return(marker); 
     } 
    } 

    class PopupPanel { 
     View popup; 
     boolean isVisible=false; 

     PopupPanel(int layout) { 
      ViewGroup parent=(ViewGroup)map.getParent(); 

      popup=getLayoutInflater().inflate(layout, parent, false); 

      popup.setOnClickListener(new View.OnClickListener() { 
       public void onClick(View v) { 
        hide(); 
       } 
      }); 
     } 

     View getView() { 
      return(popup); 
     } 

     void show(boolean alignTop) { 
      RelativeLayout.LayoutParams lp=new RelativeLayout.LayoutParams(
         RelativeLayout.LayoutParams.WRAP_CONTENT, 
         RelativeLayout.LayoutParams.WRAP_CONTENT 
      ); 

      if (alignTop) { 
       lp.addRule(RelativeLayout.ALIGN_PARENT_TOP); 
       lp.setMargins(0, 20, 0, 0); 
      } 
      else { 
       lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); 
       lp.setMargins(0, 0, 0, 60); 
      } 

      hide(); 

      ((ViewGroup)map.getParent()).addView(popup, lp); 
      isVisible=true; 
     } 

     void hide() { 
      if (isVisible) { 
       isVisible=false; 
       ((ViewGroup)popup.getParent()).removeView(popup); 
      } 
     } 
    } 

    class CustomItem extends OverlayItem { 
     Drawable marker=null; 
     boolean isHeart=false; 
     Drawable heart=null; 

     CustomItem(GeoPoint pt, String name, String snippet, Drawable marker, Drawable heart) { 
      super(pt, name, snippet); 

      this.marker=marker; 
      this.heart=heart; 
     } 

     @Override 
     public Drawable getMarker(int stateBitset) { 
      Drawable result=(isHeart ? heart : marker); 

      setState(result, stateBitset); 

      return(result); 
     } 

     void toggleHeart() { 
      isHeart=!isHeart; 
     } 
    } 

    class OverlayTask extends AsyncTask<Void, Void, Void> { 
     @Override 
     public void onPreExecute() { 
      if (sites!=null) { 
       map.getOverlays().remove(sites); 
       map.postInvalidate(); 
       sites=null; 
      } 
     } 

     @Override 
     public Void doInBackground(Void... unused) { 
      //SystemClock.sleep(5000);      // simulated work 

      sites=new SitesOverlay(); 

      return(null); 
     } 

     @Override 
     public void onPostExecute(Void unused) { 
      map.getOverlays().add(sites); 
      map.postInvalidate();   
     } 
    } 
} 

堆棧跟蹤:

java.util.ConcurrentModificationException 在java.util.ArrayList中的$ ArrayListIterator.next(ArrayList.java:573) 在com.google.android.maps.OverlayBundle.draw (OverlayBundle.java:44) at com.google.android.maps.MapView.onDraw(MapView.java:494) at android.view.View.draw(View.java:6740) at android.view.ViewGroup .drawChild(ViewGroup.java:1640) 在android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 在android.view.ViewGroup.drawChild (ViewGroup.java:1638) 在android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 在android.view.ViewGroup.drawChild(ViewGroup.java:1638) 在android.view.ViewGroup.dispatchDraw(的ViewGroup .java:1367) at android.view.View.draw(View.java:6743) at android.widget.FrameLayout.draw(FrameLayout.java:352) at android.view.ViewGroup.drawChild(ViewGroup.java :1640) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) at android.view.View.draw(View.java:6743) at android.widget.FrameLayout.draw(FrameLayout.java:352 ) 在com.android.internal.policy.impl.PhoneWindow $ DecorView.draw(PhoneWindow.java:1847) 在android.view.ViewRoot.draw(ViewRoot.java:1407 ) at android.view.ViewRoot.performTraversals(ViewRoot.java:1163) at android.view.ViewRoot.handleMessage(ViewRoot.java:1727) at android.os.Handler.dispatchMessage(Handler.java:99) 在java.lang.reflect.Method.invokeNative(本地方法) 上的android.app.ActivityThread.main(ActivityThread.java:4627) 。 lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller。運行(ZygoteInit.java:878) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636) 在dalvik.system.NativeStart.main(本機方法)

+0

請提供指向您所引用的特定代碼的鏈接。 https://github.com/commonsguy ...? – 2011-04-18 15:54:50

+0

你能從錯誤輸出中看出哪些數據結構正在產生異常嗎? – 2011-04-18 15:55:26

+0

對不起。鏈接是 - https://github.com/commonsguy/cw-advandroid/blob/master/Maps/NooYawkAsync。也增加了說明鏈接。此外,我真的不知道是什麼產生的錯誤,我會在這裏發佈錯誤 – RadicalMonkey 2011-04-18 16:03:31

回答

2

你爲什麼要刪除和替換覆蓋?

爲什麼不把覆蓋層留下,並改變它的標記?在ItemizedOverlay上再次撥打populate(),它會重新調用size()getItem()。只要確保返回新的正確數據。

你的錯誤肯定感覺它是與添加和刪除覆蓋層有關。事實上,我想也許你在doInBackground()這樣做,但你不是。因此,我會認爲,從線程的角度來看,你所做的將是安全的,從處理的角度來看,這只是矯枉過正。

+0

感謝您的快速回復,但我不是很遵循你的意思,通過改變標記。你指的是getmarker()方法嗎?我看不出我能如何設置新的經緯度。對不起,如果它很簡單,但我還是相當新的。 – RadicalMonkey 2011-04-24 18:02:53

+0

@RadicalApps:我沒有太多的話可以說我沒有在答案中說過:在'ItemizedOverlay'上調用'populate()',並在你的''size()''和'getItem()'方法上'ItemizedOverlay'返回正確的數據。地圖應該重繪自己。不要刪除覆蓋。不要添加疊加層。只需在覆蓋層上調用'populate()',使其重新加載其新標記。 – CommonsWare 2011-04-24 18:07:10

+0

啊我正在追隨着!這是我是否應該添加/刪除仍然令我困惑的標記。我會在短短的一段時間內放棄。 – RadicalMonkey 2011-04-24 18:10:59