moveCamera con CameraUpdateFactory.newLatLngBounds si arresta in modo anomalo


96

Sto utilizzando la nuova API di Google Maps per Android .

Creo un'attività che include un MapFragment. Nell'attività onResumeimposto gli indicatori nell'oggetto GoogleMap e quindi definisco un riquadro di delimitazione per la mappa che include tutti gli indicatori.

Questo sta usando il seguente pseudo codice:

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 chiamata a map.moveCamera()causa l'arresto anomalo della mia applicazione con il seguente stack:

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)

Se - invece del newLatLngBounds()metodo di fabbrica che usonewLatLngZoom() metodo, la stessa trap non si verifica.

È il onResumeposto migliore per disegnare i marcatori sull'oggetto GoogleMap o dovrei disegnare i marcatori e impostare la posizione della fotocamera da qualche altra parte?

Risposte:


133

È possibile utilizzare semplici newLatLngBounds metodo OnCameraChangeListener . Tutto funzionerà perfettamente e non è necessario calcolare le dimensioni dello schermo. Questo evento si verifica dopo il calcolo delle dimensioni della mappa (come ho capito).

Esempio:

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

1
Questo funziona perché setOnCameraChangeListener è garantito per essere eseguito almeno una volta, dopo che la mappa è stata sottoposta a layout? Questo è a prova di futuro?
Glenn Bech

3
@SteelRat Ecco perché sarei contrario all'uso della soluzione. Non sai mai quando Google lo cambia, o anche se funziona in questo modo su tutte le versioni o dispositivi Android.
Glenn Bech

1
@SteelRat Sono d'accordo, ma potrebbe essere chiamato più di una volta nella durata dell'attività? Sto solo sostenendo che anche se funziona in questo caso, non è una soluzione molto elegante. Penso che OnGlobalLayoutListener / Treelistener sia un modo più corretto per farlo.
Glenn Bech

4
magari aggiungendo map.moveCamera (CameraUpdateFactory.scrollBy (1, 1)); dopo il codice sopra farà il trucco?
MY

3
setOnCameraChangeListenerè ora deprecato
osrl

56

Quelle risposte vanno bene, ma sceglierei un approccio diverso, più semplice. Se il metodo funziona solo dopo che la mappa è stata strutturata, aspettalo:

map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
    @Override
    public void onMapLoaded() {
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30));
    }
});

1
Ho scoperto dopo molte sperimentazioni che avevo bisogno di implementare una combinazione di questa risposta e quella di Daniele sopra. A volte la mappa non era stata ancora caricata, a volte il layout non era ancora stato completato. Non potevo muovere la telecamera come volevo finché ENTRAMBI di quelli non sono accaduti.
Rapina

2
Avviso per questo metodo, dalla documentazione: "Questo evento non si attiverà se la mappa non viene mai caricata a causa di problemi di connettività o se la mappa cambia continuamente e non completa mai il caricamento a causa dell'interazione costante dell'utente con la mappa ." (enfasi mia).
stkent

1
Questo ritarda più del necessario perché attende che le tessere della mappa vengano caricate nella posizione sbagliata prima di spostarsi nella posizione corretta.
John Patterson

1
Il più delle volte ci vogliono dai 3 ai 10 secondi per sparare, il che è inaccettabile.
Nima G

Questo è il posto per spostare la telecamera. Suggerirei di utilizzare map.animateCamera anziché map.moveCamera
Bharat Dodeja

51

OK, ho risolto questo problema. Come documentato qui, l' API non può essere utilizzata pre-layout.

L'API corretta da utilizzare è descritta come:

Nota: utilizzare solo il metodo più semplice newLatLngBounds (confine, riempimento) per generare un CameraUpdate se verrà utilizzato per spostare la telecamera dopo che la mappa ha subito il layout. Durante il layout, l'API calcola i confini di visualizzazione della mappa necessari per proiettare correttamente il riquadro di delimitazione. In confronto, puoi utilizzare il CameraUpdate restituito dal metodo più complesso newLatLngBounds (boundary, width, height, padding) in qualsiasi momento, anche prima che la mappa abbia subito il layout, perché l'API calcola i confini di visualizzazione dagli argomenti che passi.

Per risolvere il problema ho calcolato le dimensioni dello schermo e ho fornito la larghezza e l'altezza a

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

Questo mi ha quindi permesso di specificare il pre-layout del riquadro di delimitazione.


18
Ma cosa succede se la mappa non occupa l'intero schermo?
theblang

Nel mio caso avevo semplicemente ipotizzato uno schermo più grande di quanto fosse in effetti e avevo bisogno di calcolare il riempimento con maggiore attenzione in modo che in realtà non fosse troppo grande. Un motivo molto più semplice.
rfay

2
Puoi mostrare come calcolarlo in base alle dimensioni dello schermo?
Daniel Gomez Rico,

Questo non si blocca, ma la larghezza e l'altezza da utilizzare sono vicine al puro ipotesi, l'area esatta da disegnare è davvero imprevedibile.
Vince

34

La soluzione è più semplice di così ...

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

Cattura IllegalStateExceptione utilizza invece il listener globale nella vista. Impostare la dimensione del limite in anticipo (pre-layout) utilizzando gli altri metodi significa che devi calcolare la dimensione di THE VIEW, non il dispositivo dello schermo. Corrispondono solo se vai a schermo intero con la tua mappa e non usi frammenti.


Finora ho usato il tuo piccolo frammento, ma ancora non riesce ... la risposta corretta è la prima :-)
cesards

1
Come / quando fallisce? non ha mai avuto problemi con questo. La prima risposta passa semplicemente una dimensione hardcoded come riserva. "Funziona" come in "non si blocca più" ma non sta facendo la stessa cosa.
Daniele Segato

@ andrea.spot non ricordo perché ho detto più semplice. Immagino che la soluzione accettata sia stata modificata nel frattempo. La soluzione attualmente accettata presuppone che la mappa occupi tutto lo schermo, il che non è sempre vero. Se non cadi in quel caso devi conoscere la dimensione della mappa o usare il mio metodo o qualcosa di simile.
Daniele Segato

controlla anche la risposta di seguito di Xingang Huang, aggiunge qualcosa.
Daniele Segato

15

Questa è la mia soluzione, in questo caso aspetta che la mappa venga caricata.

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

Semplice ed efficiente +1
Shid

14

L'aggiunta e la rimozione dei marker può essere eseguita prima del completamento del layout, ma non è possibile spostare la telecamera (tranne che utilizzando newLatLngBounds(boundary, padding)come indicato nella risposta dell'OP).

Probabilmente il miglior posto per eseguire un aggiornamento iniziale fotocamera utilizza un one-shot OnGlobalLayoutListenercome mostrato nel codice di esempio di Google , ad esempio, vedere il seguente estratto da setUpMap()in 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));
        }
    });
}


Ottengo questo errore al cambio di orientamento. L'ho trovato anche dal codice di esempio ma non ha funzionato per me. Ottengo ancora lo stesso errore.
osrl

14

La risposta accettata non avrebbe funzionato per me perché dovevo usare lo stesso codice in vari punti della mia app.

Invece di aspettare che la telecamera cambiasse, ho creato una semplice soluzione basata sul suggerimento di Lee di specificare la dimensione della mappa. Questo nel caso in cui la tua mappa abbia le dimensioni dello schermo.

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

Spero che aiuti qualcun altro!


8

La risposta accettata è, come sottolineato nei commenti, un po 'hacky. Dopo averlo implementato, ho notato una quantità di IllegalStateExceptionlog sopra accettabile nell'analisi. La soluzione che ho usato è aggiungere un file OnMapLoadedCallbackin cui CameraUpdateviene eseguito. La richiamata viene aggiunta al file GoogleMap. Dopo il caricamento completo della mappa, verrà eseguito l'aggiornamento della fotocamera.

Ciò fa sì che la mappa mostri brevemente la vista ingrandita (0,0) prima di eseguire l'aggiornamento della telecamera. Penso che questo sia più accettabile che causare arresti anomali o fare affidamento su comportamenti non documentati.


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

usa questo ha funzionato per me


Questo centra solo la mappa ma non regola dinamicamente lo zoom ai limiti.
Giovanni Di Gregorio

Possiamo calcolare i confini per più matkers usando "LatLngBounds.Builder".
Ramesh Bhupathi,

@RameshBhupathi ma rimarrà comunque una visualizzazione mappa con un centro e uno zoom.
Tima

4

In casi molto rari, il layout di MapView è finito, ma il layout di GoogleMap non è finito, di per ViewTreeObserver.OnGlobalLayoutListenersé non può fermare il crash. Ho visto il crash con la versione 5084032 del pacchetto dei servizi di Google Play. Questo raro caso potrebbe essere causato dal cambiamento dinamico della visibilità del mio MapView.

Per risolvere questo problema, ho inserito GoogleMap.OnMapLoadedCallbackin 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));
                    }
                });
            }
        }
    });
}

Interessante: se eseguo il refactoring mapView.getViewTreeObserver()in una variabile locale, si verifica il seguente errore : "IllegalStateException: questo ViewTreeObserver non è attivo, chiama di nuovo getViewTreeObserver ()" . Hai provato questo?
JJD

Se mapView.getViewTreeObserver (). IsAlive () è falso, metterei un altro fallback per map.setOnMapLoadedCallback ()
southerton

4

Ho utilizzato un approccio diverso che funziona per le versioni recenti di Google Maps SDK (9.6+) e basato su onCameraIdleListener . Come ho visto finora è il metodo di callback onCameraIdlechiamato sempre dopo onMapReady. Quindi il mio approccio assomiglia a questo pezzo di codice (considerando che è stato inserito 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
    */
}

4

Ho creato un modo per combinare i due callback: onMapReady e onGlobalLayout in un unico osservabile che verrà emesso solo quando entrambi gli eventi sono stati attivati.

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


1
In effetti è il modo più pulito per risolvere questo problema. Lo sto facendo da molto tempo ormai e nessun errore viene restituito nell'analisi anche su 1k utenti al giorno app. +1
Skyle

2

Ok, sto affrontando lo stesso problema. Ho il mio frammento con il mio SupportmapFragment, ABS e il cassetto di navigazione. Quello che ho fatto è stato:

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

E, a proposito, chiamo resetCamera()da onCreateViewdopo aver gonfiato e prima di tornare.
Ciò che fa è catturare l'eccezione la prima volta (mentre la mappa "prende una dimensione" per dirlo ...) e poi, altre volte ho bisogno di resettare la fotocamera, la mappa ha già le dimensioni e lo fa attraverso il riempimento.

Il problema è spiegato nella documentazione , dice:

Non cambiare la telecamera con questo aggiornamento della telecamera fino a quando la mappa non ha subito il layout (affinché questo metodo possa determinare correttamente il riquadro di delimitazione e il livello di zoom appropriati, la mappa deve avere una dimensione). Altrimenti IllegalStateExceptionverrà lanciato un messaggio. NON è sufficiente che la mappa sia disponibile (cioè getMap()restituisce un oggetto non nullo); anche la vista contenente la mappa deve aver subito un tracciato tale che ne siano state determinate le dimensioni. Se non puoi essere sicuro che ciò sia accaduto, utilizza newLatLngBounds(LatLngBounds, int, int, int)invece e fornisci le dimensioni della mappa manualmente.

Penso che sia una soluzione abbastanza decente. Spero che aiuti qualcuno.


1
c'è qualche ascoltatore da ascoltare quando il layout è completamente caricato. ?
Sagar Nayak

L'eccezione viene sollevata in newLatLngBounds()o in animateCamera()o in entrambi? Il ramo di cattura non porterà a una nuova eccezione?
CoolMind

1

Se è necessario attendere l'inizio di possibili interazioni con l'utente, utilizzare OnMapLoadedCallbackcome descritto nelle risposte precedenti. Tuttavia, se tutto ciò di cui hai bisogno è fornire una posizione predefinita per la mappa, non c'è bisogno di nessuna delle soluzioni descritte in quelle risposte. Entrambi MapFragmente MapViewpossono accettare un GoogleMapOptionsinizio che può fornire la posizione predefinita, va bene. L'unico trucco è non includerli direttamente nel layout perché il sistema li chiamerà senza le opzioni, ma inizializzarli dinamicamente.

Usa questo nel tuo layout:

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

e sostituisci il frammento nel tuo 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();

Oltre ad essere più veloce da avviare, non verrà mostrata prima la mappa del mondo e la telecamera si muoverà per seconda. La mappa inizierà direttamente con la posizione specificata.


0

Un altro approccio sarebbe qualcosa del tipo (supponendo che la tua vista più in alto sia un FrameLayout denominato rootContainer, anche se funzionerà fintanto che scegli sempre il tuo contenitore più in alto, indipendentemente dal tipo o dal nome che ha):

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

La modifica delle funzioni della fotocamera per funzionare solo se layoutDoneè truerisolverà tutti i tuoi problemi senza dover aggiungere funzioni extra o collegare la logica al layoutListenergestore.


0

Ho scoperto che funziona ed è più semplice delle altre soluzioni:

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

Questo riprova a chiamare dopo che il layout è stato eseguito. Potrebbe probabilmente includere una sicurezza per evitare un loop infinito.


0

Perché non usare semplicemente qualcosa di simile:

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

Perché newLatLngBounds(builder.build(), padding)non è dentro try-catch? Questa eccezione si verifica in moveCamera()?
CoolMind

0

C'è una classe helper nel repository di Google Maps che puoi sfruttare: attende che sia il layout che la mappa siano pronti prima di notificare una richiamata con GoogleMap:

La fonte originale è qui:

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

C'è anche un'implementazione di 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);
    }
}
}

0

Come affermato in OnCameraChangeListener () è deprecato , setOnCameraChangeListenerora è deprecato. Quindi dovresti sostituirlo con uno dei tre metodi:

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

Nel mio caso l'ho usato OnCameraIdleListenere al suo interno l'ho rimosso perché veniva richiamato più e più volte su qualsiasi movimento.

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

AGGIORNARE

Ho rimosso googleMap.setOnCameraIdleListenernel mio progetto, perché a volte non veniva chiamato quando veniva mostrata una mappa, ma mantenuto googleMap.setOnCameraIdleListener(clusterManager).


grazie per la tua risposta Sto già cercando una soluzione quasi uguale a questa.
Arslan Maqbool

@ArslanMaqbool, grazie! Sono in fase di elaborazione ora e ti sarò grato se condividi la tua variante.
CoolMind

mio piacere @CoolMind
Arslan Maqbool

0

Ho avuto lo stesso errore cercando di chiamare mMap.animateCamera. L'ho risolto chiamando setOnMapLoadedCallback callback nella mia funzione onMapReady come mostrato di seguito

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

   // other codes go there

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

Questo dovrebbe funzionare bene.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.