Jonathan Caryl
Jonathan Caryl

Reputation: 1330

When can you call GoogleMap.moveCamera after onMapReady from OnMapReadyCallback?

The current Android Google Maps API requires you call mapFragment.getMapAsync with a OnMapReadyCallback before you can access the GoogleMap. I assumed that once you had the GoogleMap it would then be safe to call moveCamera() but I was seeing crash reports with an IllegalStateException which said Map size can't be 0. Most likely, layout has not yet occured for the map view.

So I tried adding a ViewTreeObserver.OnPreDrawListener, and moving the moveCamera() call to the onPreDraw method, as the docs for that say "At this point, all views in the tree have been measured and given a frame". But I still see some crash reports with the same problem. I can't find any documentation for this — there's questions like moveCamera with CameraUpdateFactory.newLatLngBounds crashes but they pre-date the getMapAsync API, so they're not much help.

Upvotes: 14

Views: 4818

Answers (3)

mbelsky
mbelsky

Reputation: 6588

I had the same issue. This google maps library throws the exception when an app try to change the camera with this camera update until the map has undergone layout (in order for this method to correctly determine the appropriate bounding box and zoom level, the map must have a size). It described here.

It's my solution:

@Override
public void onMapReady(GoogleMap googleMap) {
    googleMap.setOnMapLoadedCallback(this);
}

@Override
public void onMapLoaded() {
    googleMap.animateCamera(CameraUpdateFactory.newLatLngBounds(…));
}

Upvotes: 11

Peter McLennan
Peter McLennan

Reputation: 503

I had the same problem. I adapted a solution from the link you provided, which seems to work for me. In onCreate():

rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    public void onGlobalLayout() {displayMap();}
});

OnGlobalLayoutListener() seems to be called multiple times per layout, so perhaps a more precisely targetted listener would be better. To avoid the inefficiency of manipulating the map more than necessary, I used a boolean mMapInitialised.

onMapReady():

@Override public void onMapReady(GoogleMap map) {
    mMap =  map;
    displayMap();   // if width of MapFragment is known
}

displayMap():

void displayMap() {
    // Check that mMap has been initialised AND the width of the MapFragment has been set:
    if (mMapInitialised || mMap==null) return;
    if (mMapFragment.getView().getRight() <= 0) return;
    LatLngBounds bounds = new LatLngBounds(new LatLng(mLat_min,mLng_min), new LatLng(mLat_max,mLng_max));
    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 10);
    mMap.moveCamera(cameraUpdate);
    mMapInitialised = true;
}

Upvotes: 0

Nanoc
Nanoc

Reputation: 2381

You can do anything you want right after you get onMapReady(GoogleMap googleMap) called.

This is working right now in mi app:

mapFragment.getMapAsync(new OnMapReadyCallback() {

            @Override
            public void onMapReady(GoogleMap googleMap) {

                map = googleMap;
                map.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(usr.getLatitud(), usr.getLongitud()), 14.6f));
            }
});

Upvotes: 0

Related Questions