refreshing map ItemizedOverlay gives ArrayIndexOutOfBoundsException
Asked Answered
Y

2

6

Using the com.google.android.maps API, I've got a MapActivity which uses ItemizedOverlay to place several (up to about 1000) icons on a MapView. I want to refresh (or perhaps just add to the list of) the icons when the LocationListener detects the device has moved a certain distance (currently 5 meters, but that's just for testing).

I've added setLastFocusedIndex(-1) and populate(), but my ItemizedOverlay is still crashing. I think it's crashing when I add more items to the list, but sometimes it seems to crash even if I don't move my phone. It crashes on the first update. I can't tell from LogCat exactly what's triggering the error.

My MapActivity is based off various tutorials:

EDIT: tweaked code to do a batch update of items but it still crashes

public class NearbyActivity extends MapActivity implements VenueCatalogListener {
    private final String TAG = this.getClass().getSimpleName();

    List<Overlay> mapOverlays;
    HelloItemizedOverlay itemizedOverlay;

    private MapController mapController;
    private MapView mapView;
    private LocationManager locationManager;

    private int latE6;
    private int lonE6;

    private Location current_location;
    private VenuesFromServer venues_from_server;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        venues_from_server = new VenuesFromServer(this);
        setupViews();
    }

    private void setupViews() {
        setContentView(R.layout.nearby_view);


        RelativeLayout linearLayout = (RelativeLayout) findViewById(R.id.mapMainLayout);

        mapView = new MapView(this, PreferencesManager.CLUBBERIA_MAPS_API_KEY);
        initializeMap();

        linearLayout.addView(mapView);
    }

    private void initializeMap() {
        mapView.setKeepScreenOn(true);
        mapView.setClickable(true);
        mapView.setBuiltInZoomControls(true);
        mapController = mapView.getController();
        mapController.setZoom(mapView.getMaxZoomLevel()-5); // Zoom 1 is world view

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, new GeoUpdateHandler());

        mapOverlays = mapView.getOverlays();
        if(itemizedOverlay == null) {
            Drawable drawable = this.getResources().getDrawable(R.drawable.icon);
            itemizedOverlay = new HelloItemizedOverlay(drawable);
            mapOverlays.add(itemizedOverlay);
        }
    }

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

    public class GeoUpdateHandler implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            if(current_location == null) {
                current_location = location;
            }

            int lat = (int) (location.getLatitude() * 1E6);
            int lng = (int) (location.getLongitude() * 1E6);
            GeoPoint point = new GeoPoint(lat, lng);
            if(current_location.distanceTo(location) > 5) {
                // this kicks off an async task that will call back to venueListUpdated() below
                venues_from_server.getVenueJSONFromServer(location.getLatitude(), location.getLongitude(), 19);
            }
            mapController.animateTo(point); //  mapController.setCenter(point);
        }

        @Override
        public void onProviderDisabled(String provider) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    }

    @Override
    public void venueListUpdated() {

        // Base.B.arrayVenuesMap is an ArrayList<Venue>
        for(int i=0;i<Base.B.arrayVenuesMap.size();i++) {
            Venue _venue = Base.B.arrayVenuesMap.get(i);
            latE6 =  (int) (_venue.latitude*1e6);
            lonE6 = (int) (_venue.longitude*1e6);
            GeoPoint point = new GeoPoint(latE6, lonE6);
            OverlayItem overlayitem = new OverlayItem(point, _venue.name, "");
            Drawable drawable = this.getResources().getDrawable(R.drawable.icon);

            itemizedOverlay.addOverlay(overlayitem, drawable);
        }
        itemizedOverlay.batchPopulate();
    }
}

My ItemizedOverlay looks like this:

public class HelloItemizedOverlay extends ItemizedOverlay<OverlayItem> {

    private ArrayList<OverlayItem> mOverlays = null;

    public HelloItemizedOverlay(Drawable defaultMarker) {
        super(boundCenterBottom(defaultMarker));
        mOverlays = new ArrayList<OverlayItem>();
        setLastFocusedIndex(-1);
        populate();
    }

    public void addOverlay(OverlayItem overlay, Drawable defaultMarker) {
        if(!mOverlays.contains(overlay)) {
            setLastFocusedIndex(-1);
            overlay.setMarker(boundCenterBottom(defaultMarker));
            mOverlays.add(overlay);
        }
    }

    public void batchPopulate() {
        setLastFocusedIndex(-1);
        populate();
    }

    @Override
    protected OverlayItem createItem(int i) {
        return mOverlays.get(i);
    }

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

Logcat features the following lines:

11-24 18:28:02.245: D/AsyncJSONClient(18382): starting connect with this many pairs: 0; thread 17
11-24 18:28:02.255: E/AndroidRuntime(18382): FATAL EXCEPTION: main
11-24 18:28:02.255: E/AndroidRuntime(18382): java.lang.ArrayIndexOutOfBoundsException
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.google.android.maps.ItemizedOverlay.getIndexToDraw(ItemizedOverlay.java:211)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.google.android.maps.ItemizedOverlay.draw(ItemizedOverlay.java:240)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.google.android.maps.Overlay.draw(Overlay.java:179)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:42)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.google.android.maps.MapView.onDraw(MapView.java:530)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.View.draw(View.java:6918)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.View.draw(View.java:6921)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.widget.FrameLayout.draw(FrameLayout.java:357)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.View.draw(View.java:6921)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.widget.FrameLayout.draw(FrameLayout.java:357)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.View.draw(View.java:6921)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.widget.FrameLayout.draw(FrameLayout.java:357)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1947)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewRoot.draw(ViewRoot.java:1539)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewRoot.performTraversals(ViewRoot.java:1275)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.view.ViewRoot.handleMessage(ViewRoot.java:1876)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.os.Handler.dispatchMessage(Handler.java:99)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.os.Looper.loop(Looper.java:123)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at android.app.ActivityThread.main(ActivityThread.java:3728)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at java.lang.reflect.Method.invokeNative(Native Method)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at java.lang.reflect.Method.invoke(Method.java:507)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
11-24 18:28:02.255: E/AndroidRuntime(18382):    at dalvik.system.NativeStart.main(Native Method)
11-24 18:28:02.255: W/ActivityManager(308):   Force finishing activity com.clubberia.android/.ClubberiaMain

How can I occasionally add items to ItemizedOverlay without crashes?

Young answered 24/11, 2011 at 10:5 Comment(0)
D
3

ni know its a bit old, but @cgwylie is almost right..

you should call populate() after updating overlays values... and then you can call the postInvalidate()

Drew answered 17/9, 2012 at 15:48 Comment(0)
D
0

When you change items in an ItemizedOverlay, you need to call postInvalidate() on your MapView to let it know you've adjusted the overlays so it won't try and draw items that aren't in the list again.

In your venueListUpdated() you may try adding mapView.postInvalidate() after calling itemizedOverlay.addOverlay(overlayitem, drawable) to resolve your problem.

Drusilladrusus answered 24/11, 2011 at 10:28 Comment(2)
hmm. I just tried your suggestion, but it didn't work. Thanks anyway!Young
Cool, sorry it didn't work, it's solved the problem in the past for me.Drusilladrusus

© 2022 - 2024 — McMap. All rights reserved.