Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[android] Problem with CameraIdleListener #12260

Closed
swsong12 opened this issue Jun 29, 2018 · 17 comments
Closed

[android] Problem with CameraIdleListener #12260

swsong12 opened this issue Jun 29, 2018 · 17 comments
Assignees
Labels
Android Mapbox Maps SDK for Android

Comments

@swsong12
Copy link

Platform: android
Mapbox SDK version: 6.2.0

Steps to trigger behavior

  1. pinch to zoom

Issue

When I try to pinch to zoom (in/out) OnCameraIdleListener is called multiple times. We tried couple of work arounds such as using 200ms timeout after when camera idle is detected. Yet, this method is not optimal for user experience because timeout seems to vary among different devices. In other words, this work around works like a charm on some devices, but not on the other devices.

So I am curious if there is anyway to figure out the zoom level, which the user will land after user releases his or her fingers.

Or

Is there any way to figure out the optimal timeout value? Currently, we are using guessed value of 200ms (really rough estimate).

Thank you!

@LukasPaczos LukasPaczos added the Android Mapbox Maps SDK for Android label Jun 29, 2018
@LukasPaczos
Copy link
Member

@swsong12 Thanks for reaching out! Firing multiple onCameraIdle callbacks is currently an expected behavior as we are distinguishing between movement initiated by actual pointers changing position and an animated movement.
That said, I'm sure we can improve this experience so keeping this ticket to track the progress.

@swsong12
Copy link
Author

@LukasPaczos

Is there anyway to figure out the target zoom level right after pinch? In other words, the user will land on a specific zoom level after user releases his or her fingers. Can we know this final/targeted zoom level user lands on as soon as user releases his/her fingers?

@LukasPaczos
Copy link
Member

@swsong12, thanks for opening and suggesting #12274.
Keeping this ticket open to track the improvement to the camera idle listener.

@pawelwichniewicz
Copy link

@LukasPaczos Do you have any information how long it will take to improve / fix camera idle listener? I'm having same issues as in #10923 . I'm using 6.2.1 version of the library and this is a problem for me.

@LukasPaczos
Copy link
Member

@pawelwichniewicz we're tracking the issue but can't provide any concrete timeline for the required changes yet.

@mf16
Copy link

mf16 commented Jul 20, 2018

@pawelwichniewicz @swsong12
This is especially frustrating because it causes performance issues when updating markers based on camera position. In our case the map would "stutter" until it reaches its final resting place. I implemented the following to get rid of this stutter. The downside to this is marker drawing will be delayed a bit, but in our case that is a much better user experience.

Edit: I've changed this code since writing it, since the mIsCameraIdle boolean in onCameraMove should be all you need. You can see the previous version with a timer if you look at this comment's history. I've found ~750ms to be about enough time to not trigger while a user is scrolling along, but quick enough to be responsive. I also had to add a little sumthin sumthin to onMarkerClick to stop the onCameraIdle callback (from making the marker info invisible) when on a device.

final Handler mIsCameraIdleHandler = new Handler();
private boolean mIsCameraIdle = false;

@Override
public void onCameraMove(){
    // Set true to prevent screen from freezing while user is moving the map at all
    mIsCameraIdle = false;
}

@Override
public boolean onMarkerClick(Marker marker) {
    mIsCameraIdleHandler.removeCallbacksAndMessages(null);
}

@Override
public void onCameraIdle() {
    if(mIsCameraIdle){
        // Do resource intensive marker querying & drawing here
    } else {
        mIsCameraIdle = true;

        mIsCameraIdleHandler.removeCallbacksAndMessages(null);
        mIsCameraIdleHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                onCameraIdle();
            }
        }, 750);
   }
}

@kjkrum
Copy link

kjkrum commented Sep 4, 2018

@mf16 I've been using something similar, but I've tested on a few devices and found that a delay of only 50 ms is sufficient. The difference may be that I've gone back to 5.x due to an unrelated performance issue with 6.x.

public abstract class OnCameraReallyIdleListener implements OnCameraMoveListener, OnCameraIdleListener {
	private final Handler mHandler = new Handler(Looper.getMainLooper());
	private final long mDelay;
	private Runnable mCallback;

	public OnCameraReallyIdleListener(final long delay) {
		mDelay = delay;
	}

	@Override
	public final void onCameraMove() {
		removeCallbacks();
	}

	@Override
	public final void onCameraIdle() {
		removeCallbacks();
		mCallback = () -> {
			onCameraReallyIdle();
			mCallback = null;
		};
		mHandler.postDelayed(mCallback, mDelay);
	}

	public final void removeCallbacks() {
		if(mCallback != null) {
			mHandler.removeCallbacks(mCallback);
			mCallback = null;
		}
	}

	abstract public void onCameraReallyIdle();
}

@LukasPaczos
Copy link
Member

To give a little bit more context here, the issue originates from the separation of direct movement and velocity animated movement. The idea of separation and general solution are being tracked in mapbox/mapbox-gestures-android#13.

@LukasPaczos
Copy link
Member

Thanks for the patience on this one. The solution has been shipped with the 6.6.0-alpha.2. Feel free to reach out if there are still any issues.

@Hassan-Fa
Copy link

i'm still having the issue with 6.6.0_alpha.2

getting moveCanceled , onMove and Idle callBacks at the same time when panning :(

@mkrussel77
Copy link

I'm still seeing this in 6.7.0

@percula
Copy link

percula commented Feb 14, 2019

I adapted @kjkrum 's idea using Kotlin Coroutines:

   val scope = LifecycleScope()

   init {
        lifecycle.addObserver(scope)
    }

   private var cameraIdleJob: Job? = null

    override fun onCameraIdle() {
        cameraIdleJob?.cancel()
        cameraIdleJob = scope.launch {
            delay(50)
            // DO WORK HERE
        }
    }

    override fun onCameraMove() {
        cameraIdleJob?.cancel()
    }

Like him, I found that a 50ms delay seems to work.

@LukasPaczos
Copy link
Member

@percula if you are referring to

When I try to pinch to zoom (in/out) OnCameraIdleListener is called multiple times.

it should've been resolved. Are you still hitting the issue?

@percula
Copy link

percula commented Feb 15, 2019

@LukasPaczos , yeah I was still getting the issue in Mapbox 6.8.1. It was being called maybe a dozen times when the map first loaded (maybe also on pinch/zoom but I haven't tested that). On start, I reposition the map to the user's current location, but that should only result in 2 calls, not a dozen.

@LukasPaczos
Copy link
Member

Sounds like a different issue then, would you mind opening a new ticket with reproduction steps and logs? Thank you!

@percula
Copy link

percula commented Feb 15, 2019

Thanks! I'll do some more debugging just to make sure it's not my fault. If my implementation looks good, I'll open a new ticket.

@hardslk
Copy link

hardslk commented Mar 5, 2020

When I add geoJsonlayer on map and also bind onCameraIdle event that's why I don't get onMarkerClick event lister.please help.Thanks in Advance.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Android Mapbox Maps SDK for Android
Projects
None yet
Development

No branches or pull requests

9 participants