1

이 문제는 내 머리를 들여 놓았습니다. 이전에 여러 가지 문제에 대한 답변을 찾았으므로 사람들이 다시 마법을 쓸 수 있기를 바랍니다.mylocation 오버레이와 타이머를 사용하는 ConcurrentModificationException

내 앱의 일부는 Google지도 API를 사용하여지도에 오버레이를 표시합니다. 오버레이 클래스)뿐만 아니라 mylocationoverlay를 사용하는 사용자 위치. 이제 mylocationoverlay를 활성화하지 않으면 모든 것이 잘 작동하지만 앱이 활성화되면 앱이 ConcurrentModificationException으로 종료됩니다.

이제 타이머가 위치가 항상 바뀌면서 오버레이를 새로 고치는 데 사용됩니다. 이를 위해 비동기 작업을 사용하여 오버레이를 제거하고 업데이트 된 위치로 새 오버레이를 추가합니다. 백그라운드에서 mylocationoverlay가 비슷한 일을한다고 가정하는 것이 맞습니까? 그 가정이 유효하다면, mylocationoverlay와 나의 비동기 태스크가 동일한 어레이를 반복/수정하려고 시도하고 있다는 결론에 도달했습니다. 유일한 것은 이것이 일어나지 않게하는 방법을 모릅니다!

여기에 코드를 게시 할 수는 없지만 commonsguy에서 만든 github에서 가져온 예제 코드를 사용하여 동일한 문제를 일으키도록 수정했습니다.

정말 도움이 될 것이므로 정말 실망 스럽습니다. 미리 감사드립니다. 그리고 긴 설명을 유감스럽게 생각합니다!

편집 : commonsguy 코드에 대한 링크입니다 - https://github.com/commonsguy/cw-advandroid/blob/master/Maps/NooYawkAsync/

편집 2 : 추가 오류 추적 자바 코드 후.

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();   
     } 
    } 
} 

스택 추적 : com.google.android.maps.OverlayBundle.draw에서의 java.util.ArrayList $ ArrayListIterator.next (ArrayList.java:573) 에서

java.util.ConcurrentModificationException (OverlayBundle.java:44) at com.google.android.maps.MapView.onDraw (MapView.java:494) android.view.View.draw (View.java:6740) android.view.ViewGroup .drawChild (ViewGroup.java:1640) android.view.ViewGroup.dispatchDraw (ViewGroup.java:1367) android.view.ViewGroup.drawChild android.view.ViewGroup.dispatchDraw에서 android.view.ViewGroup.drawChild (ViewGroup.java:1638) 에서 android.view.ViewGroup.dispatchDraw (ViewGroup.java:1367)에서 (ViewGroup.java:1638) (뷰 그룹 .java : 1367) android.view.View.draw (View.java:6743) at android.widget.FrameLayout.draw (FrameLayout.java:352) at android.view.ViewGroup.drawChild (ViewGroup.java) : 1640) android.view.ViewGroup.dispatchDraw (ViewGroup.java:1367) at android.view.View.draw (View.java:6743) at android.widget.FrameLayout.draw (FrameLayout.java:352)) at com.android.internal.policy.impl.PhoneWindow $ DecorView.draw (PhoneWindow.java:1847) at android.view.ViewRoot.draw (ViewRoot.java:1407)) android.view.ViewRoot.performTraversals (ViewRoot.java:1163) android.view.ViewRoot.handleMessage (ViewRoot.java:1727에서 ) android.os.Handler.dispatchMessage (Handler.java:99에서 )에서 android.os.Looper.loop (Looper.java:123) android.app.ActivityThread.main (ActivityThread.java:4627) at java.lang.reflect.Method.invokeNative (네이티브 메소드) at java. lang.reflect.Method.invoke (Method.java:521) at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.dalvik.system.NativeStart.main에서 com.android.internal.os.ZygoteInit.main (ZygoteInit.java:636) 에서 실행 (ZygoteInit.java:878) (기본 방법)

+0

참조 할 특정 코드에 대한 링크를 제공해주십시오. https://github.com/commonsguy ...? –

+0

오류 출력에서 ​​어떤 데이터 구조가 예외를 생성하는지 알 수 있습니까? –

+0

죄송합니다. 링크는 https://github.com/commonsguy/cw-advandroid/blob/master/Maps/NooYawkAsync입니다. 설명에 대한 링크도 추가되었습니다. 또한 실제로 오류가 무엇인지 알려지지 않습니다. 잠시 후에 오류를 게시하겠습니다. – RadicalMonkey

답변

2

왜 제거하고 오버레이 교체?

오버레이를 그대로두고 마커를 변경하지 않으시겠습니까? ItemizedOverlay에서 populate()으로 다시 전화하면 size()getItem() 번으로 다시 전화 할 것입니다. 새로운 올바른 데이터를 반환하십시오.

오버레이 추가 및 제거와 관련된 오류가 발생했습니다. 사실, 나는 아마 당신이 doInBackground()에서 그렇게하고 있다고 생각했지만, 그렇지는 않습니다. 따라서, 나는 당신이하고있는 일이 쓰레딩의 관점에서 안전 할 것이라고 생각했을 것입니다. 단지 처리의 관점에서 지나치게 과장 될 것입니다.

+0

빠른 답장을 보내 주셔서 감사합니다. 그러나 마커를 변경하면 무슨 뜻인지 알 수 없습니다. getmarker() 메소드를 언급하고 있습니까? 나는 어떻게 그런 식으로 새로운 위도를 설정할 수 있는지 모르겠다. 미안하지만 단순하지만 아직은 상당히 새롭다. – RadicalMonkey

+0

@RadicalApps : 대답 자체는 말하지 않았는데,'ItemizedOverlay'에서'populate()'를 호출하고,'ItemizeOverlay'에서'size()'와'getItem()'메소드를 가지고 있습니다. 'ItemizedOverlay'는 올바른 데이터를 반환합니다. 지도 자체를 다시 그려야합니다. 오버레이를 제거하지 마십시오. 오버레이를 추가하지 마십시오. 새 데이터로 마커를 다시로드하려면 오버레이에서'populate()'를 호출하기 만하면됩니다. – CommonsWare

+0

아, 지금 다음과 같습니다! 여전히 나를 혼란스럽게하는 마커를 추가/제거해야하는지 여부가있었습니다. 나는 잠시 후에 그것을 줄 것이다. – RadicalMonkey