osmdroid: Zoom Button Crash in 6.1.0

Issue Type

[X] Bug

Description and/or steps/code to reproduce the problem

Plugging 6.1.0 into gradle to replace 6.0.3 in my App, all things so far seem fine. All but the (standard) zoom buttons: These bottons relyably crash 100% of the time after app start. With plenty of stack trace which all seem repeations of this (one click creates hundreds and so far I only checked manually):

2019-03-25 09:26:07.704 ? E/AndroidRuntime:     at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
2019-03-25 09:26:07.704 ? E/AndroidRuntime:     at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1133)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1547)
        at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1339)
        at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1471)
        at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146)
        at android.animation.AnimationHandler.access$100(AnimationHandler.java:37)
        at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1170)
        at android.view.Choreographer.doCallbacks(Choreographer.java:984)
        at android.view.Choreographer.doFrame(Choreographer.java:806)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1158)
        at android.os.Handler.handleCallback(Handler.java:873)
2019-03-25 09:26:07.704 ? E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6863)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Once the user has done some manual (gesture or in my App location bookmarks) zooming or location change, this does not happen any more. But when the user hits zoom directly after start it crashes relyably.

The stack traces seem to depend on Android version, on Android 4.2.2 I get the following:

03-25 09:42:27.976 de.spieleck.app.badgers.debug E/AndroidRuntime: FATAL EXCEPTION: main java.lang.StackOverflowError

(which matches to the amount of output on Android 9 where log is just to fast to keep the start of problems in Android Studio memory).

Environment

My Badge®s App, Android 4.2.2, 9 checked here

If it’s a bug, version(s) of android this affects:

A9, 4.2.2

Version of osmdroid the issue relates to:

6.1.0

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 39 (14 by maintainers)

Commits related to this issue

Most upvoted comments

if we are all in concur on this, i can merge and get a new version rolled out today or tomorrow

Success today!

The issue is related to any app having a Snappable overlay (an OwnLocationOverlay):

This code in setZoomLevel https://github.com/osmdroid/osmdroid/blob/8bcb806f8d763e4a1e36813c8ac6b7e763cb2b6f/osmdroid-android/src/main/java/org/osmdroid/views/MapView.java#L500 gets true from onSnapItem https://github.com/osmdroid/osmdroid/blob/832e0813d394e83106c5cdc3beb642d38d5dbade/osmdroid-android/src/main/java/org/osmdroid/views/overlay/DefaultOverlayManager.java#L270 and continuously calls animateTo leading to SO:

			if (this.getOverlayManager().onSnapToItem((int) mMultiTouchScaleInitPoint.x,
					(int) mMultiTouchScaleInitPoint.y, snapPoint, this)) {
				IGeoPoint geoPoint = pj.fromPixels(snapPoint.x, snapPoint.y, null, false);
				getController().animateTo(geoPoint);
			}

and onSnapItem:

    public boolean onSnapToItem(final int x, final int y, final Point snapPoint, final IMapView pMapView) {
        for (final Overlay overlay : this.overlaysReversed()) {
            if (overlay instanceof Snappable) {
                if (((Snappable) overlay).onSnapToItem(x, y, snapPoint, pMapView)) {
                    return true;

I could repro stack overflow by hardcoding return true; in onSnapToItem; patch this below.and zoom out to stack overflow at will in Osmdroid-android test app!

Index: osmdroid-android/src/main/java/org/osmdroid/views/overlay/DefaultOverlayManager.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- osmdroid-android/src/main/java/org/osmdroid/views/overlay/DefaultOverlayManager.java	(revision b6ea341a9bc2658011f827f57edeaf3baea51fc8)
+++ osmdroid-android/src/main/java/org/osmdroid/views/overlay/DefaultOverlayManager.java	(date 1558697029000)
@@ -265,11 +265,12 @@
     @Override
     public boolean onSnapToItem(final int x, final int y, final Point snapPoint, final IMapView pMapView) {
         for (final Overlay overlay : this.overlaysReversed()) {
-            if (overlay instanceof Snappable) {
-                if (((Snappable) overlay).onSnapToItem(x, y, snapPoint, pMapView)) {
-                    return true;
-                }
-            }
+//            if (overlay instanceof Snappable) {
+//                if (((Snappable) overlay).onSnapToItem(x, y, snapPoint, pMapView)) {
+//                    return true;
+//                }
+//            }
+            return true;
         }
 
         return false;

I created this patch to get keyboard working in Android Emulator:

Index: OpenStreetMapViewer/src/main/java/org/osmdroid/ExtraSamplesActivity.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- OpenStreetMapViewer/src/main/java/org/osmdroid/ExtraSamplesActivity.java	(revision b6ea341a9bc2658011f827f57edeaf3baea51fc8)
+++ OpenStreetMapViewer/src/main/java/org/osmdroid/ExtraSamplesActivity.java	(date 1558657192000)
@@ -63,12 +63,15 @@
         if (mMapView==null)
             return super.onKeyUp(keyCode,event);
         switch (keyCode) {
-            case KeyEvent.KEYCODE_PAGE_DOWN:
+            case KeyEvent.KEYCODE_EQUALS:
                 mMapView.getController().zoomIn();
                 return true;
-            case KeyEvent.KEYCODE_PAGE_UP:
+            case KeyEvent.KEYCODE_MINUS:
                 mMapView.getController().zoomOut();
                 return true;
+            case KeyEvent.KEYCODE_BACKSLASH:
+                mMapView.getController().zoomTo(12);
+                return true;
         }
         return super.onKeyUp(keyCode,event);
     }

With the change above, I tried to zoom to 12 (pressing BACKSLASH, which is what I start at in my app) in Osmdroid tests (ExtraSamplesActivity), and then out (MINUS) which I understand zooms out to 11. The zoomAnimatorListener are the same in ExtraSamplesActivity and my app; in ExtraSamplesActivity it seems to work fine… In my app I hit zoom 11 and keep hitting 11 in an endless loop leading to stack overflow (valueAnimator.getAnimatedValue() keeps on returning the same value of 1.0f): image

On both sides I am at b6ea341a9bc2658011f827f57edeaf3baea51fc8

I use avd (AS 3.4 on Ubuntu/Intel). I find android keyboard hooks v useful. Maybe you just need to send few zoomIn events:

    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
        mapViewWrap.run {
            return when (keyCode) {
                KeyEvent.KEYCODE_8 -> simulateGpsLocationFromKeyboard()
                KeyEvent.KEYCODE_W -> simulateMovingFwdFromKeyboard()
                KeyEvent.KEYCODE_A -> simulateTurningLeftFromKeyboard()
                KeyEvent.KEYCODE_D -> simulateTurningRightFromKeyboard()
                KeyEvent.KEYCODE_EQUALS -> zoomIn()
                KeyEvent.KEYCODE_MINUS -> zoomOut()
                KeyEvent.KEYCODE_DPAD_DOWN -> down()
                KeyEvent.KEYCODE_DPAD_UP -> up()
                KeyEvent.KEYCODE_DPAD_LEFT -> left()
                KeyEvent.KEYCODE_DPAD_RIGHT -> right()
                KeyEvent.KEYCODE_DPAD_CENTER -> zoomInToLastKnownLocation()
                KeyEvent.KEYCODE_N -> { showNearestFragment(); true }
                KeyEvent.KEYCODE_P -> OpenAddWptToRouteEvent().sendRx()
                else -> super.onKeyUp(keyCode, event)
            }
        }
    }

in class inheriting from MapView:
    fun zoomIn(): Boolean {
        return mapView?.controller?.zoomIn() ?: false
    }

Ok, I got it. You should PERFECTLY center the map to your location (so for example using enableFollowLocation and wait for it to center). Then the app crashes because there is an infinite recursion.

It’s caused by the fact that each time the zoom updates, osm tries to “snap” to the user location using org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay#onSnapToItem .

I can revert https://github.com/osmdroid/osmdroid/pull/1237 for now and try to fix both issues later.

I have exactly the same problem (both my working app and a simple test app with MapView and LocationOverlay). Tested on Android 5 (AVD) and Android 9 (Samsung S9) It only happens when zoom in / out just after app start. I use the buttons that appear after tapping The beginning of my error log is:

    --------- beginning of crash
2019-03-29 10:05:25.480 28752-28752/pl.at7.testapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: pl.at7.testapp, PID: 28752
    java.lang.StackOverflowError: stack size 8MB
        at android.util.LongSparseLongArray.clear(LongSparseLongArray.java:217)
        at android.view.View.requestLayout(View.java:21977)
        at org.osmdroid.views.MapView.setMapScroll(MapView.java:1781)
        at org.osmdroid.views.MapView.setExpectedCenter(MapView.java:1807)
        at org.osmdroid.views.MapView.setExpectedCenter(MapView.java:1823)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:480)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1522)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1110)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)
        at org.osmdroid.views.MapController$MapAnimatorListener.onAnimationUpdate(MapController.java:520)
        at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1522)
        at android.animation.ValueAnimator.end(ValueAnimator.java:1110)
        at org.osmdroid.views.MapController.animateTo(MapController.java:167)
        at org.osmdroid.views.MapController.animateTo(MapController.java:137)
        at org.osmdroid.views.MapController.animateTo(MapController.java:183)
        at org.osmdroid.views.MapController.animateTo(MapController.java:129)
        at org.osmdroid.views.MapView.setZoomLevel(MapView.java:492)

…and repeated several times

My code in ‘empty’ MainActivity:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 /* permissions here*/

        setContentView(R.layout.activity_main);
        Context ctx = getApplicationContext();
        Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
        map = findViewById(R.id.map);
        mapController = map.getController();
        mapController.setZoom(16.0);
        map.setTileSource(TileSourceFactory.MAPNIK);

        GpsMyLocationProvider provider = new GpsMyLocationProvider(ctx);
        provider.addLocationSource(LocationManager.GPS_PROVIDER);
        MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(provider, map);
        mLocationOverlay.enableMyLocation();
        mLocationOverlay.enableFollowLocation();
  }
    public void onResume(){
        super.onResume();
        map.onResume(); 
    }

    public void onPause(){
        super.onPause();
        map.onPause();
    }