knowing when the card has stopped scrolling (as & ldquo; moveend & rdquo; in javascript API)


I need to detect when a MapView has been scrolled or zoomed, like the "moveend" event in the javascript API. I'd like to wait until the view has stopped moving, so I can then detect if I need to query my server for items withing the viewing rectangle, and if so send out a request. (actually I send a request for a slightly larger area than the viewing rectangle)

Obviously, I'd rather not send out a request for data if the view is still moving. But even worse is that I don't know that I need to send another request, leaving areas of the map missing markers.

Currently I am subclassing MapView and handling the onTouchEvent as follows:

 public boolean onTouchEvent(android.view.MotionEvent ev) {
        super.onTouchEvent (ev);
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            GeoPoint center = getMapCenter();
            int latSpan = getLatitudeSpan(), lngSpan = getLongitudeSpan();
            /* (check if it has moved enough to need a new set of data)  */
        return true;

Problem is, I don't know if the view has stopped, since scrolling tends to have inertia and can keep going past the "ACTION_UP" event.

Is there some event I can tap into that will alert me when a mapview is done moving (or zooming)? If not, has anyone written logic to detect this? In theory I could make a guess by looking at all the actions, and set something to come along bit later and check it...but...that seems messy and a PITA. But if someone has already written it.... :)

I don't really have a satisfactory solution to this problem, but I can tell what I did to partially solve it.

  • I subclassed MapView and overrode the computeScroll() method, which gets the current centre-point of the map and compares it with the last-known centre-point (stored as a volatile field in the subclass). If the centre-point has changed, it fires an event to the listener of the map (I defined a custom listener interface for this).
  • The listener is an activity that instantiates a subclass of AsyncTask and executes it. This task pauses for 100ms in its doInBackGround() method, before performing the server data fetch.
  • When the listener activity receives a second map-move event (which it will do because of the stepping effect of the map movement), it checks the status of the just-executed AsyncTask. If that task is still running, it will cancel() it. It then creates a new task, and executes that.

The overall effect is that when the listeners get the flurry of map-moved events a few milliseconds apart, the only one that actually triggers the task to perform the server-fetch is the last one in the sequence. The downside is that it introduces a slight delay between the map movement happening, and the server fetch occurring.

I'm not happy with it, it's ugly, but it mitigates the problem. I would love to see a better solution to this.