moveCamera con CameraUpdateFactory.newLatLngBounds se bloquea

96

Estoy utilizando la nueva API de Google Maps para Android .

Creo una actividad que incluye un MapFragment. En la actividad onResume, configuro los marcadores en el objeto GoogleMap y luego defino un cuadro delimitador para el mapa que incluye todos los marcadores.

Esto está usando el siguiente pseudo código:

LatLngBounds.Builder builder = new LatLngBounds.Builder();
while(data) {
   LatLng latlng = getPosition();
   builder.include(latlng);
}
CameraUpdate cameraUpdate = CameraUpdateFactory
   .newLatLngBounds(builder.build(), 10);
map.moveCamera(cameraUpdate);

La llamada a map.moveCamera()hace que mi aplicación se bloquee con la siguiente pila:

Caused by: java.lang.IllegalStateException: 
    Map size should not be 0. Most likely, layout has not yet 

    at maps.am.r.b(Unknown Source)
    at maps.y.q.a(Unknown Source)
    at maps.y.au.a(Unknown Source)
    at maps.y.ae.moveCamera(Unknown Source)
    at com.google.android.gms.maps.internal.IGoogleMapDelegate$Stub
        .onTransact(IGoogleMapDelegate.java:83)
    at android.os.Binder.transact(Binder.java:310)
    at com.google.android.gms.maps.internal.IGoogleMapDelegate$a$a
        .moveCamera(Unknown Source)
    at com.google.android.gms.maps.GoogleMap.moveCamera(Unknown Source)
    at ShowMapActivity.drawMapMarkers(ShowMapActivity.java:91)
    at ShowMapActivity.onResume(ShowMapActivity.java:58)
    at android.app.Instrumentation
        .callActivityOnResume(Instrumentation.java:1185)
    at android.app.Activity.performResume(Activity.java:5182)
    at android.app.ActivityThread
        .performResumeActivity(ActivityThread.java:2732)

Si, en lugar del newLatLngBounds()método de fábrica, uso el newLatLngZoom()método, entonces no ocurre la misma trampa.

¿Es el onResumemejor lugar para dibujar los marcadores en el objeto GoogleMap o debería dibujar los marcadores y establecer la posición de la cámara en otro lugar?

Sotavento
fuente

Respuestas:

133

Puede usar el método newLatLngBounds simple en OnCameraChangeListener . Todo funcionará perfectamente y no es necesario calcular el tamaño de la pantalla. Este evento ocurre después del cálculo del tamaño del mapa (según tengo entendido).

Ejemplo:

map.setOnCameraChangeListener(new OnCameraChangeListener() {

    @Override
    public void onCameraChange(CameraPosition arg0) {
        // Move camera.
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 10));
        // Remove listener to prevent position reset on camera move.
        map.setOnCameraChangeListener(null);
    }
});
Paul Annekov
fuente
1
Esto funciona porque se garantiza que setOnCameraChangeListener se ejecutará al menos una vez, después de que el mapa se haya diseñado. ¿Es esto una prueba de futuro?
Glenn Bech
3
@SteelRat Es por eso que estaría en contra de usar la solución. Nunca se sabe cuándo Google cambia esto, o incluso si funciona de esa manera en todas las versiones o dispositivos de Android.
Glenn Bech
1
@SteelRat Estoy de acuerdo, pero ¿podría ser llamado más de una vez durante la vida de la actividad? Solo estoy argumentando que incluso si funciona en este caso, no es una solución muy elegante. Creo que OnGlobalLayoutListener / Treelistener es una forma más correcta de hacerlo.
Glenn Bech
4
tal vez agregando map.moveCamera (CameraUpdateFactory.scrollBy (1, 1)); después de que el código anterior hará el truco?
MI
3
setOnCameraChangeListenerahora está en desuso
osrl
56

Esas respuestas están bien, pero yo optaría por un enfoque diferente, uno más simple. Si el método solo funciona después de diseñar el mapa, solo espere:

map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
    @Override
    public void onMapLoaded() {
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30));
    }
});
Leandro
fuente
1
Después de mucha experimentación, descubrí que necesitaba implementar una combinación de esta respuesta y la de Daniele anterior. A veces, el mapa aún no se había cargado, a veces el diseño aún no se había completado. No pude mover la cámara como deseaba hasta que sucedieron AMBOS.
RobP
2
Advertencia para este método, de los documentos: "Este evento no se activará si el mapa nunca se carga debido a problemas de conectividad, o si el mapa cambia continuamente y nunca completa la carga debido a que el usuario interactúa constantemente con el mapa ". (énfasis mío).
2014
1
Esto demora más de lo necesario porque espera a que los mosaicos del mapa se carguen en la posición incorrecta antes de moverse a la posición correcta.
John Patterson
1
La mayoría de las veces, se tarda entre 3 y 10 segundos en disparar, lo cual es inaceptable.
Nima G
Este es el lugar para mover la cámara. Sugeriría usar map.animateCamera en lugar de map.moveCamera
Bharat Dodeja
51

OK, resolví esto. Como se documenta aquí, la API no se puede utilizar antes del diseño.

La API correcta para usar se describe como:

Nota: Utilice únicamente el método más simple newLatLngBounds (límite, relleno) para generar una actualización de cámara si se va a utilizar para mover la cámara después de que el mapa se haya diseñado. Durante el diseño, la API calcula los límites de visualización del mapa que se necesitan para proyectar correctamente el cuadro delimitador. En comparación, puede usar CameraUpdate devuelto por el método más complejo newLatLngBounds (límite, ancho, alto, relleno) en cualquier momento, incluso antes de que el mapa haya sido diseñado, porque la API calcula los límites de visualización a partir de los argumentos que pasa.

Para solucionar el problema, calculé el tamaño de mi pantalla y proporcioné el ancho y el alto para

public static CameraUpdate newLatLngBounds(
    LatLngBounds bounds, int width, int height, int padding)

Esto me permitió especificar el diseño previo del cuadro delimitador.

Sotavento
fuente
18
Pero, ¿y si el mapa no ocupa toda la pantalla?
theblang
En mi caso, había asumido una pantalla más grande de lo que estaba en efecto, y necesitaba calcular el relleno con más cuidado para que de hecho fuera no demasiado grande. Una razón mucho más sencilla.
rfay
2
¿Puede mostrar cómo calcularlo en función del tamaño de la pantalla?
Daniel Gómez Rico
Esto no se bloquea, pero el ancho y la altura que se utilizarán son casi simples conjeturas, el área exacta que se dibujará es realmente impredecible.
Vince
34

La solución es más simple que eso ...

// Pan to see all markers in view.
try {
    this.gmap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
} catch (IllegalStateException e) {
    // layout not yet initialized
    final View mapView = getFragmentManager()
       .findFragmentById(R.id.map).getView();
    if (mapView.getViewTreeObserver().isAlive()) {
        mapView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @SuppressWarnings("deprecation")
            @SuppressLint("NewApi")
            // We check which build version we are using.
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                    mapView.getViewTreeObserver()
                        .removeGlobalOnLayoutListener(this);
                } else {
                    mapView.getViewTreeObserver()
                        .removeOnGlobalLayoutListener(this);
                }
                gmap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
            }
        });
    }
}

En su lugar, captura IllegalStateExceptiony usa el oyente global en la vista. Establecer el tamaño del límite por adelantado (diseño previo) utilizando los otros métodos significa que debe calcular el tamaño de LA VISTA, no el dispositivo de pantalla. Solo coinciden si vas a pantalla completa con tu mapa y no usas fragmentos.

Daniele Segato
fuente
Hasta ahora he estado usando su pequeño fragmento, pero aún falla ... la respuesta correcta es la primera :-)
cesards
1
¿Cómo / cuándo falla? nunca tuve un problema con esto. La primera respuesta simplemente le pasa un tamaño codificado como una alternativa. "Funciona" como en "ya no se bloquea", pero no hace lo mismo.
Daniele Segato
@ andrea.spot No recuerdo por qué dije más simple. Supongo que la solución aceptada se ha editado mientras tanto. La solución aceptada actual asume que su mapa ocupa toda la pantalla, lo que no siempre es cierto. Si no caes en ese caso necesitas saber el tamaño del mapa o usar mi método o algo similar.
Daniele Segato
También verifique la respuesta a continuación de Xingang Huang, le agrega un poco.
Daniele Segato
15

Esta es mi solución, solo espere hasta que se cargue el mapa en ese caso.

final int padding = getResources().getDimensionPixelSize(R.dimen.spacing);    

try {
    mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(pCameraBounds, padding));
} catch (IllegalStateException ise) {

    mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {

        @Override
        public void onMapLoaded() {
            mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(pCameraBounds, padding));
        }
    });
}
pl3kn0r
fuente
Simple y eficiente +1
Shid
14

La adición y eliminación de marcadores se puede realizar antes de completar el diseño, pero no se puede mover la cámara (excepto usando newLatLngBounds(boundary, padding) como se indica en la respuesta del OP).

Probablemente el mejor lugar para llevar a cabo una actualización inicial de la cámara utiliza un one-shot OnGlobalLayoutListenercomo se muestra en el código de ejemplo de Google , por ejemplo, véase el siguiente extracto de setUpMap()en MarkerDemoActivity.java :

// Pan to see all markers in view.
// Cannot zoom to bounds until the map has a size.
final View mapView = getSupportFragmentManager()
    .findFragmentById(R.id.map).getView();
if (mapView.getViewTreeObserver().isAlive()) {
    mapView.getViewTreeObserver().addOnGlobalLayoutListener(
    new OnGlobalLayoutListener() {
        @SuppressLint("NewApi") // We check which build version we are using.
        @Override
        public void onGlobalLayout() {
            LatLngBounds bounds = new LatLngBounds.Builder()
                    .include(PERTH)
                    .include(SYDNEY)
                    .include(ADELAIDE)
                    .include(BRISBANE)
                    .include(MELBOURNE)
                    .build();
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
              mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            } else {
              mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
            mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
        }
    });
}
StephenT
fuente
Recibo este error al cambiar de orientación. También encontré esto en un código de muestra, pero esto no funcionó para mí. Sigo recibiendo el mismo error.
osrl
14

La respuesta aceptada no me funcionaría porque tuve que usar el mismo código en varios lugares de mi aplicación.

En lugar de esperar a que cambiara la cámara, creé una solución simple basada en la sugerencia de Lee de especificar el tamaño del mapa. Esto es en caso de que su mapa sea del tamaño de la pantalla.

// Gets screen size
int width = getResources().getDisplayMetrics().widthPixels;
int height = getResources().getDisplayMetrics().heightPixels;
// Calls moveCamera passing screen size as parameters
map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), width, height, 10));

¡Espero que ayude a alguien más!

Teo Inke
fuente
8

La respuesta aceptada es, como se señala en los comentarios, un poco hacky. Después de implementarlo, noté una cantidad de IllegalStateExceptionregistros superior a la aceptable en análisis. La solución que utilicé es agregar un OnMapLoadedCallbacken el que CameraUpdatese realiza el. La devolución de llamada se agrega alGoogleMap . Una vez que su mapa se cargue por completo, se realizará la actualización de la cámara.

Esto hace que el mapa muestre brevemente la vista alejada (0,0) antes de realizar la actualización de la cámara. Sin embargo, creo que esto es más aceptable que causar accidentes o depender de un comportamiento indocumentado.

theblang
fuente
5
 map.moveCamera(CameraUpdateFactory.newLatLngZoom(bounds.getCenter(),10));

usa esto funcionó para mí

Ramesh Bhupathi
fuente
Esto solo centra el mapa pero no ajusta dinámicamente el zoom a los límites.
Giovanni Di Gregorio
Podemos calcular límites para más matkers usando "LatLngBounds.Builder".
Ramesh Bhupathi
@RameshBhupathi, pero seguirá siendo una vista de mapa con un centro y un zoom.
Tima
4

En casos muy raros, el diseño de MapView está terminado, pero el diseño de GoogleMap no está terminado, ViewTreeObserver.OnGlobalLayoutListener sí mismo no puede detener el bloqueo. Vi el bloqueo con el paquete de servicios de Google Play versión 5084032. Este caso poco común puede deberse al cambio dinámico de la visibilidad de mi MapView.

Para resolver este problema, incrustado GoogleMap.OnMapLoadedCallbacken onGlobalLayout(),

if (mapView.getViewTreeObserver().isAlive()) {
    mapView.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        @SuppressWarnings("deprecation")
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            } else {
                mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
            try {
                map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 5));
            } catch (IllegalStateException e) {
                map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
                    @Override
                    public void onMapLoaded() {
                        Log.d(LOG_TAG, "move map camera OnMapLoadedCallback");
                        map.moveCamera(CameraUpdateFactory
                            .newLatLngBounds(bounds, 5));
                    }
                });
            }
        }
    });
}
Alpha Huang
fuente
Interesante: si refactorizo mapView.getViewTreeObserver()en una variable local, se produce el siguiente error : "IllegalStateException: este ViewTreeObserver no está vivo, llame a getViewTreeObserver () de nuevo" . ¿Intentaste esto?
JJD
Si resulta que mapView.getViewTreeObserver (). IsAlive () es falso, pondría una alternativa más para map.setOnMapLoadedCallback ()
southerton
4

Utilicé un enfoque diferente que funciona para versiones recientes de Google Maps SDK (9.6+) y basado en onCameraIdleListener . Como veo hasta ahora, el método de devolución de llamada se onCameraIdlellama siempre después onMapReady. Entonces, mi enfoque se parece a este fragmento de código (considerando que está incluido Activity):

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // set content view and call getMapAsync() on MapFragment
}

@Override
public void onMapReady(GoogleMap googleMap) {
    map = googleMap;
    map.setOnCameraIdleListener(this);
    // other initialization stuff
}

@Override
public void onCameraIdle() {
    /* 
       Here camera is ready and you can operate with it. 
       you can use 2 approaches here:

      1. Update the map with data you need to display and then set
         map.setOnCameraIdleListener(null) to ensure that further events
         will not call unnecessary callback again.

      2. Use local boolean variable which indicates that content on map
         should be updated
    */
}
Viacheslav
fuente
4

Creé una forma de combinar las dos devoluciones de llamada: onMapReady y onGlobalLayout en un solo observable que se emitirá solo cuando ambos eventos se hayan activado.

https://gist.github.com/abhaysood/e275b3d0937f297980d14b439a8e0d4a

Abhay Sood
fuente
1
De hecho, es la forma más limpia de resolver esto. Estoy haciendo esto durante mucho tiempo y no se devuelve ningún error en el análisis incluso en la aplicación de 1k usuarios por día. +1
Skyle
2

Ok, estoy enfrentando el mismo problema. Tengo mi fragmento con mi SupportmapFragment, ABS y cajón de navegación. Lo que hice fue:

public void resetCamera() {

    LatLngBounds.Builder builderOfBounds = new LatLngBounds.Builder();
    // Set boundaries ...
    LatLngBounds bounds = builderOfBounds.build();
    CameraUpdate cu;
    try{
        cu = CameraUpdateFactory.newLatLngBounds(bounds,10);
        // This line will cause the exception first times 
        // when map is still not "inflated"
        map.animateCamera(cu); 
        System.out.println("Set with padding");
    } catch(IllegalStateException e) {
        e.printStackTrace();
        cu = CameraUpdateFactory.newLatLngBounds(bounds,400,400,0);
        map.animateCamera(cu);
        System.out.println("Set with wh");
    }

    //do the rest...
}

Y, por cierto, llamo resetCamera()desde onCreateViewdespués de inflar y antes de regresar.
Lo que hace es captar la excepción la primera vez (mientras que el mapa "adquiere un tamaño" como una forma de decirlo ...) y luego, otras veces necesito reiniciar la cámara, el mapa ya tiene tamaño y lo hace mediante el relleno.

El problema se explica en la documentación , dice:

No cambie la cámara con esta actualización de la cámara hasta que el mapa se haya diseñado (para que este método determine correctamente el cuadro delimitador y el nivel de zoom adecuados, el mapa debe tener un tamaño). De lo contrario IllegalStateException, se lanzará un . NO es suficiente que el mapa esté disponible (es decir, getMap()devuelve un objeto no nulo); la vista que contiene el mapa también debe haber sido diseñada de manera que se hayan determinado sus dimensiones. Si no puede estar seguro de que esto haya ocurrido, utilice newLatLngBounds(LatLngBounds, int, int, int)en su lugar y proporcione las dimensiones del mapa manualmente.

Creo que es una solución bastante decente. Espero que ayude a alguien.

unmultimedio
fuente
1
¿Hay algún oyente que escuche cuando el diseño está completamente cargado? ?
Sagar Nayak
¿Se plantea la excepción en newLatLngBounds()o en animateCamera(), o en ambos? ¿No conducirá el catch-branch a una nueva excepción?
CoolMind
1

Si necesita esperar a que comiencen las posibles interacciones del usuario, utilice OnMapLoadedCallbackcomo se describe en las respuestas anteriores. Pero, si todo lo que necesita es proporcionar una ubicación predeterminada para el mapa, no hay necesidad de ninguna de las soluciones descritas en esas respuestas. Ambos MapFragmenty MapViewpueden aceptar un GoogleMapOptionsinicio que puede proporcionar la ubicación predeterminada correctamente. El único truco es no incluirlos directamente en su diseño porque el sistema los llamará sin las opciones en ese momento, sino inicializarlos dinámicamente.

Use esto en su diseño:

<FrameLayout
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

y reemplace el fragmento en su onCreateView():

GoogleMapOptions options = new GoogleMapOptions();
options.camera(new CameraPosition.Builder().target(location).zoom(15).build());
// other options calls if required

SupportMapFragment fragment = (SupportMapFragment) getFragmentManager().findFragmentById(R.id.map);
if (fragment == null) {
  FragmentTransaction transaction = getFragmentManager().beginTransaction();
  fragment = SupportMapFragment.newInstance(options);
  transaction.replace(R.id.map, fragment).commit();
  getFragmentManager().executePendingTransactions();
}
if (fragment != null)
  GoogleMap map = fragment.getMap();

Además de ser más rápido para comenzar, no se mostrará un mapa del mundo primero y una cámara se moverá en segundo lugar. El mapa comenzará directamente con la ubicación especificada.

Gábor
fuente
0

Otro enfoque sería algo como (Suponiendo que su vista superior es un FrameLayout nombrado rootContainer, aunque funcionará siempre que siempre elija su contenedor superior sin importar qué tipo o nombre tenga):

((FrameLayout)findViewById(R.id.rootContainer)).getViewTreeObserver()
    .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        public void onGlobalLayout() {
            layoutDone = true;
        }
    });

Modificar las funciones de su cámara para que solo funcionen si layoutDonees así trueresolverá todos sus problemas sin tener que agregar funciones adicionales o conectar la lógica al layoutListenercontrolador.

Machinarius
fuente
0

Encontré que esto funciona y es más simple que las otras soluciones:

private void moveMapToBounds(final CameraUpdate update) {
    try {
        if (movedMap) {
            // Move map smoothly from the current position.
            map.animateCamera(update);
        } else {
            // Move the map immediately to the starting position.
            map.moveCamera(update);
            movedMap = true;
        }
    } catch (IllegalStateException e) {
        // Map may not be laid out yet.
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                moveMapToBounds(update);
            }
        });
    }
}

Esto intenta la llamada nuevamente después de que se haya ejecutado el diseño. Probablemente podría incluir una seguridad para evitar un bucle infinito.

John Patterson
fuente
0

¿Por qué no usar algo como esto?

CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(builder.build(), padding);
try {
    map.moveCamera(cameraUpdate);
} catch (Exception e) {
    int width = getResources().getDisplayMetrics().widthPixels;
    int height = getResources().getDisplayMetrics().heightPixels;
    cameraUpdate = CameraUpdateFactory.newLatLngBounds(builder.build(), width, height, padding);
    map.moveCamera(cameraUpdate);
}
Hristo Lalev
fuente
¿Por qué newLatLngBounds(builder.build(), padding)no está adentro try-catch? ¿Esta excepción ocurre en moveCamera()?
CoolMind
0

Hay una clase auxiliar en el repositorio de Google Maps que puede aprovechar: espera que tanto el diseño como el mapa estén listos antes de notificar una devolución de llamada con GoogleMap:

La fuente original está aquí:

https://github.com/googlemaps/android-samples/blob/7ee737b8fd6d39c77f8b3716ba948e1ce3730e61/ApiDemos/java/app/src/main/java/com/example/mapdemo/OnMapAndViewReadyListener.java

También hay una implementación de Kotlin:

https://github.com/googlemaps/android-samples/blob/master/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt

public class OnMapAndViewReadyListener implements OnGlobalLayoutListener, OnMapReadyCallback {

/** A listener that needs to wait for both the GoogleMap and the View to be initialized. */
public interface OnGlobalLayoutAndMapReadyListener {
    void onMapReady(GoogleMap googleMap);
}

private final SupportMapFragment mapFragment;
private final View mapView;
private final OnGlobalLayoutAndMapReadyListener devCallback;

private boolean isViewReady;
private boolean isMapReady;
private GoogleMap googleMap;

public OnMapAndViewReadyListener(
        SupportMapFragment mapFragment, OnGlobalLayoutAndMapReadyListener devCallback) {
    this.mapFragment = mapFragment;
    mapView = mapFragment.getView();
    this.devCallback = devCallback;
    isViewReady = false;
    isMapReady = false;
    googleMap = null;

    registerListeners();
}

private void registerListeners() {
    // View layout.
    if ((mapView.getWidth() != 0) && (mapView.getHeight() != 0)) {
        // View has already completed layout.
        isViewReady = true;
    } else {
        // Map has not undergone layout, register a View observer.
        mapView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    // GoogleMap. Note if the GoogleMap is already ready it will still fire the callback later.
    mapFragment.getMapAsync(this);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    // NOTE: The GoogleMap API specifies the listener is removed just prior to invocation.
    this.googleMap = googleMap;
    isMapReady = true;
    fireCallbackIfReady();
}

@SuppressWarnings("deprecation")  // We use the new method when supported
@SuppressLint("NewApi")  // We check which build version we are using.
@Override
public void onGlobalLayout() {
    // Remove our listener.
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
    } else {
        mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }
    isViewReady = true;
    fireCallbackIfReady();
}

private void fireCallbackIfReady() {
    if (isViewReady && isMapReady) {
        devCallback.onMapReady(googleMap);
    }
}
}
dazza5000
fuente
0

Como se indica en OnCameraChangeListener () está en desuso , setOnCameraChangeListenerahora está en desuso. Por lo tanto, debe reemplazarlo con uno de los tres mtehods:

  • GoogleMap.OnCameraMoveStartedListener
  • GoogleMap.OnCameraMoveListener
  • GoogleMap.OnCameraIdleListener

En mi caso lo usé OnCameraIdleListenery por dentro lo quité porque se invocaba una y otra vez ante cualquier movimiento.

googleMap.setOnCameraIdleListener {
    googleMap.setOnCameraIdleListener(null) // It removes the listener.
    googleMap.moveCamera(track)
    googleMap.cameraPosition
    clusterManager!!.cluster()
    // Add another listener to make ClusterManager correctly zoom clusters and markers.
    googleMap.setOnCameraIdleListener(clusterManager)
}

ACTUALIZAR

Lo eliminé googleMap.setOnCameraIdleListeneren mi proyecto, porque a veces no se llamaba cuando se mostraba un mapa, pero se conservaba googleMap.setOnCameraIdleListener(clusterManager).

CoolMind
fuente
gracias por tu respuesta Ya estoy descubriendo una solución casi igual a esta.
Arslan Maqbool
@ArslanMaqbool, ¡gracias! Estoy en proceso ahora y le agradeceré si comparte su variante.
CoolMind
mi placer @CoolMind
Arslan Maqbool
0

Tuve el mismo error al intentar llamar a mMap.animateCamera. Lo resolví llamando a setOnMapLoadedCallback callback en mi función onMapReady como se muestra a continuación

public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

   // other codes go there

    mMap.setOnMapLoadedCallback(() -> {
            //Your code where exception occurs goes here...
            
        });
}

Esto debería funcionar bien.

Paul Kumchi
fuente