moveCamera avec CameraUpdateFactory.newLatLngBounds plante

96

J'utilise la nouvelle API Google Maps pour Android .

Je crée une activité qui inclut un MapFragment. Dans l'activité, onResumeje place les marqueurs dans l'objet GoogleMap, puis je définis un cadre de délimitation pour la carte qui comprend tous les marqueurs.

Cela utilise le pseudo code suivant:

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

L'appel à map.moveCamera()provoque le blocage de mon application avec la pile suivante:

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 - au lieu de la newLatLngBounds()méthode d'usine, j'utilise la newLatLngZoom()méthode, le même piège ne se produit pas.

Est-ce onResumele meilleur endroit pour dessiner les marqueurs sur l'objet GoogleMap ou dois-je dessiner les marqueurs et définir la position de la caméra ailleurs?

Lee
la source

Réponses:

133

Vous pouvez utiliser la méthode newLatLngBounds simple dans OnCameraChangeListener . Tout fonctionnera parfaitement et vous n'avez pas besoin de calculer la taille de l'écran. Cet événement se produit après le calcul de la taille de la carte (si je comprends bien).

Exemple:

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
la source
1
Cela fonctionne car setOnCameraChangeListener est garanti de s'exécuter au moins une fois, après que la carte a subi une mise en page? Est-ce la preuve du futur?
Glenn Bech
3
@SteelRat C'est pourquoi je serais contre l'utilisation de la solution. Vous ne savez jamais quand Google change cela, ni même si cela fonctionne de cette façon sur toutes les versions ou appareils Android.
Glenn Bech
1
@SteelRat Je suis d'accord, mais il peut être appelé plus d'une fois dans la durée de vie de l'activité? Je fais simplement valoir que même si cela fonctionne dans ce cas, ce n'est pas une solution très élégante. Je pense que le OnGlobalLayoutListener / Treelistener est une manière plus correcte de procéder.
Glenn Bech
4
peut-être en ajoutant map.moveCamera (CameraUpdateFactory.scrollBy (1, 1)); après le code ci-dessus fera le truc?
Mon
3
setOnCameraChangeListenerest maintenant obsolète
osrl
56

Ces réponses sont très bien, mais j'opterais pour une approche différente, plus simple. Si la méthode ne fonctionne qu'après la mise en page de la carte, attendez-la:

map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
    @Override
    public void onMapLoaded() {
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30));
    }
});
Leandro
la source
1
J'ai trouvé après beaucoup d'expérimentation que j'avais besoin de mettre en œuvre une combinaison de cette réponse et de celle de Daniele ci-dessus. Parfois, la carte n'avait pas encore été chargée, parfois la mise en page n'était pas encore terminée. Je ne pouvais pas déplacer la caméra comme je le souhaitais jusqu'à ce que les deux se produisent.
RobP
2
Avertissement pour cette méthode, de la documentation: "Cet événement ne se déclenchera pas si la carte ne se charge jamais en raison de problèmes de connectivité, ou si la carte change continuellement et ne termine jamais le chargement en raison de l'interaction constante de l'utilisateur avec la carte ." (c'est moi qui souligne).
stkent
1
Cela retarde plus longtemps que nécessaire car il attend que les tuiles de la carte se chargent à la mauvaise position avant de passer à la bonne position.
John Patterson
1
La plupart du temps, il faut entre 3 et 10 secondes pour tirer, ce qui est inacceptable.
Nima G
C'est l'endroit où déplacer la caméra. Je suggérerais d'utiliser map.animateCamera plutôt que map.moveCamera
Bharat Dodeja
51

OK, j'ai travaillé sur ça. Comme documenté ici, cette API ne peut pas être utilisée avant la mise en page.

L'API correcte à utiliser est décrite comme suit:

Remarque: utilisez uniquement la méthode plus simple newLatLngBounds (boundary, padding) pour générer un CameraUpdate si elle doit être utilisée pour déplacer la caméra une fois que la carte a été mise en page. Pendant la mise en page, l'API calcule les limites d'affichage de la carte qui sont nécessaires pour projeter correctement le cadre de sélection. En comparaison, vous pouvez utiliser le CameraUpdate retourné par la méthode plus complexe newLatLngBounds (limite, largeur, hauteur, remplissage) à tout moment, même avant que la carte n'ait subi une mise en page, car l'API calcule les limites d'affichage à partir des arguments que vous passez.

Pour résoudre le problème, j'ai calculé la taille de mon écran et fourni la largeur et la hauteur à

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

Cela m'a ensuite permis de spécifier la pré-mise en page de la boîte englobante.

Lee
la source
18
Mais que faire si la carte n'occupe pas tout l'écran?
theblang
Dans mon cas, j'avais juste supposé un écran plus grand que ce qui était en effet, et j'avais besoin de calculer le rembourrage plus soigneusement pour qu'il ne soit en fait pas trop grand. Une raison bien plus simple.
rfay
2
Pouvez-vous montrer comment le calculer en fonction de la taille de l'écran?
Daniel Gomez Rico
Cela ne plante pas mais la largeur et la hauteur à utiliser sont proches de pures suppositions, la zone exacte à dessiner est vraiment imprévisible.
Vince
34

La solution est plus simple que ça ...

// 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));
            }
        });
    }
}

Attrapez IllegalStateExceptionet utilisez plutôt l'écouteur global sur la vue. La définition de la taille liée à l'avance (pré-mise en page) à l'aide des autres méthodes signifie que vous devez calculer la taille de THE VIEW, pas celle du périphérique d'écran. Ils ne correspondent que si vous passez en plein écran avec votre carte et n'utilisez pas de fragments.

Daniele Segato
la source
Jusqu'à présent, j'utilise votre petit extrait de code, mais il échoue toujours ... la bonne réponse est la première :-)
cesards
1
Comment / quand ça échoue? jamais eu de problème avec ça. La première réponse lui transmet simplement une taille codée en dur comme solution de secours. "Ça marche" comme dans "ça ne plante plus" mais ça ne fait pas la même chose.
Daniele Segato
@ andrea.spot Je ne me souviens pas pourquoi j'ai dit plus simple. Je suppose que la solution acceptée a été modifiée entre-temps. La solution actuellement acceptée suppose que votre carte occupe tout l'écran, ce qui n'est pas toujours vrai. Si vous ne tombez pas dans ce cas, vous devez soit connaître la taille de la carte, soit utiliser ma méthode ou quelque chose de similaire.
Daniele Segato
Vérifiez également la réponse ci-dessous par Xingang Huang, cela y ajoute un peu.
Daniele Segato
15

C'est ma solution, attendez que la carte soit chargée dans ce cas.

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
la source
Simple et efficace +1
Shid
14

L'ajout et la suppression de marqueurs peuvent être effectués avant la mise en page, mais le déplacement de la caméra ne peut pas (sauf en utilisant newLatLngBounds(boundary, padding)comme indiqué dans la réponse du PO).

Probablement le meilleur endroit pour effectuer une mise à jour initiale de la caméra utilise un one-shot OnGlobalLayoutListenercomme indiqué dans un exemple de code de Google , par exemple , voir l'extrait suivant 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
la source
J'obtiens cette erreur lors du changement d'orientation. J'ai également trouvé cela à partir d'un exemple de code, mais cela n'a pas fonctionné pour moi. Je reçois toujours la même erreur.
osrl
14

La réponse acceptée ne fonctionnait pas pour moi car je devais utiliser le même code à différents endroits de mon application.

Au lieu d'attendre que la caméra change, j'ai créé une solution simple basée sur la suggestion de Lee de spécifier la taille de la carte. C'est au cas où votre carte aurait la taille de l'écran.

// 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));

J'espère que cela aide quelqu'un d'autre!

Teo Inke
la source
8

La réponse acceptée est, comme indiqué dans les commentaires, un peu hacky. Après l'avoir implémenté, j'ai remarqué une quantité de IllegalStateExceptionjournaux plus acceptable dans l'analyse. La solution que j'ai utilisée est d'ajouter un OnMapLoadedCallbackdans lequel le CameraUpdateest effectué. Le rappel est ajouté au GoogleMap. Une fois votre carte chargée, la mise à jour de la caméra sera effectuée.

Cela fait que la carte affiche brièvement la vue agrandie (0,0) avant d'effectuer la mise à jour de la caméra. Je pense que c'est plus acceptable que de provoquer des accidents ou de se fier à un comportement non documenté.

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

utilise ça ça a marché pour moi

Ramesh Bhupathi
la source
Cela ne fait que centrer la carte mais n'ajuster pas dynamiquement le zoom aux limites.
Giovanni Di Gregorio
Nous pouvons calculer les limites pour plus de matkers en utilisant "LatLngBounds.Builder".
Ramesh Bhupathi
@RameshBhupathi mais cela restera une vue cartographique avec un centre et un zoom.
Tima
4

Dans de très rares cas, la mise en page MapView est terminée, mais la mise en page GoogleMap n'est pas terminée, ViewTreeObserver.OnGlobalLayoutListenerelle - même ne peut pas arrêter le plantage. J'ai vu le crash avec le package de services Google Play version 5084032. Ce cas rare peut être causé par le changement dynamique de la visibilité de mon MapView.

Pour résoudre ce problème, j'EMBEDDED GoogleMap.OnMapLoadedCallbackdans 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
la source
Intéressant: Si je refactorise mapView.getViewTreeObserver()en une variable locale l' erreur suivante se produit: "IllegalStateException: ce ViewTreeObserver n'est pas vivant, appelez à nouveau getViewTreeObserver ()" . Avez-vous essayé cela?
JJD
Si mapView.getViewTreeObserver (). IsAlive () est faux, je mettrais une autre solution de secours pour map.setOnMapLoadedCallback ()
southerton
4

J'ai utilisé une approche différente qui fonctionne pour les versions récentes du SDK Google Maps (9.6+) et basée sur onCameraIdleListener . Comme je le vois jusqu'à présent, c'est la méthode de rappel onCameraIdleappelée toujours après onMapReady. Donc, mon approche ressemble à ce morceau de code (compte tenu de sa mise en place 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
la source
4

J'ai créé un moyen de combiner les deux rappels: onMapReady et onGlobalLayout en une seule observable qui n'émettra que lorsque les deux événements auront été déclenchés.

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

Abhay Sood
la source
1
C'est en fait le moyen le plus propre de résoudre ce problème. Je fais cela depuis longtemps maintenant et aucune erreur n'est renvoyée dans les analyses, même sur 1 000 utilisateurs par jour. +1
Skyle
2

Ok, je suis confronté au même problème. J'ai mon fragment avec mon SupportmapFragment, ABS et le tiroir de navigation. Ce que j'ai fait était:

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...
}

Et, en passant, je vous appelle resetCamera()de onCreateViewaprès gonflage et avant de retourner.
Ce que cela fait, c'est attraper l'exception la première fois (alors que la carte "prend une taille" pour le dire ...) et ensuite, d'autres fois, je dois réinitialiser la caméra, la carte a déjà une taille et le fait par remplissage.

Le problème est expliqué dans la documentation , il est dit:

Ne changez pas la caméra avec cette mise à jour de la caméra tant que la carte n'a pas été mise en page (pour que cette méthode détermine correctement la zone de délimitation et le niveau de zoom appropriés, la carte doit avoir une taille). Sinon, un IllegalStateExceptionsera jeté. Il ne suffit PAS que la carte soit disponible (c. getMap()-à-d. Renvoie un objet non nul); la vue contenant la carte doit également avoir subi une mise en page telle que ses dimensions aient été déterminées. Si vous ne pouvez pas être sûr que cela s'est produit, utilisez à la newLatLngBounds(LatLngBounds, int, int, int)place et fournissez les dimensions de la carte manuellement.

Je pense que c'est une solution assez décente. J'espère que ça aide quelqu'un.

unmultimedio
la source
1
y a-t-il un auditeur à écouter lorsque la mise en page est complètement chargée. ?
Sagar Nayak
L'exception est-elle levée dans newLatLngBounds()ou dans animateCamera(), ou dans les deux? La branche catch ne conduira-t-elle pas à une nouvelle exception?
CoolMind
1

Si vous devez attendre le début des interactions utilisateur possibles, utilisez OnMapLoadedCallbackcomme décrit dans les réponses précédentes. Mais, si tout ce dont vous avez besoin est de fournir un emplacement par défaut pour la carte, aucune des solutions décrites dans ces réponses n'est nécessaire. Les deux MapFragmentet MapViewpeuvent accepter un GoogleMapOptionsau début qui peut fournir l'emplacement par défaut. La seule astuce est de ne pas les inclure directement dans votre layout car le système les appellera alors sans les options mais de les initialiser dynamiquement.

Utilisez ceci dans votre mise en page:

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

et remplacez le fragment dans votre 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();

En plus d'être plus rapide au démarrage, il n'y aura pas de carte du monde affichée en premier et un mouvement de caméra en second. La carte commencera directement avec l'emplacement spécifié.

Gábor
la source
0

Une autre approche serait quelque chose comme (en supposant que votre vue la plus haute soit un FrameLayout nommé rootContainer, même si cela fonctionnera tant que vous choisissez toujours votre conteneur le plus haut, quel que soit son type ou son nom):

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

Modification de vos fonctions de l' appareil au travail que si layoutDoneest - truerésoudra tous vos problèmes sans avoir à ajouter des fonctions supplémentaires ou câbler logique au layoutListenergestionnaire.

Machinarius
la source
0

J'ai trouvé que cela fonctionnait et était plus simple que les autres solutions:

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);
            }
        });
    }
}

Cela tente de nouveau l'appel après l'exécution de la mise en page. Pourrait probablement inclure une sécurité pour éviter une boucle infinie.

John Patterson
la source
0

Pourquoi ne pas simplement utiliser quelque chose comme ceci:

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
la source
Pourquoi newLatLngBounds(builder.build(), padding)ne pas essayer-catch? Cette exception se produit-elle dans moveCamera()?
CoolMind
0

Il existe une classe d'assistance dans le référentiel Google Maps que vous pouvez utiliser - elle attend que la mise en page et la carte soient prêtes avant de notifier un rappel avec GoogleMap:

La source originale est ici:

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

Il existe également une implémentation 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
la source
0

Comme indiqué dans OnCameraChangeListener () est obsolète , setOnCameraChangeListenerest désormais obsolète. Vous devriez donc le remplacer par l'une des trois méthodes suivantes:

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

Dans mon cas, je l'ai utilisé OnCameraIdleListeneret à l'intérieur je l'ai retiré car il était invoqué encore et encore sur n'importe quel mouvement.

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)
}

METTRE À JOUR

J'ai supprimé googleMap.setOnCameraIdleListenerdans mon projet, car il n'était parfois pas appelé lorsqu'une carte était affichée, mais conservé googleMap.setOnCameraIdleListener(clusterManager).

CoolMind
la source
merci pour votre réponse.Je trouve déjà une solution presque identique à celle-ci.
Arslan Maqbool
@ArslanMaqbool, merci! Je suis en cours de traitement et je vous serai reconnaissant si vous partagez votre variante.
CoolMind
mon plaisir @CoolMind
Arslan Maqbool
0

J'ai eu la même erreur en essayant d'appeler mMap.animateCamera. Je l'ai résolu en appelant le rappel setOnMapLoadedCallback dans ma fonction onMapReady comme indiqué ci-dessous

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

   // other codes go there

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

Cela devrait fonctionner correctement.

Paul Kumchi
la source