Ich benutze die neue Android Google Maps API .
Ich erstelle eine Aktivität, die ein MapFragment enthält. In der Aktivität onResume
setze ich die Markierungen in das GoogleMap-Objekt und definiere dann einen Begrenzungsrahmen für die Karte, der alle Markierungen enthält.
Dies verwendet den folgenden Pseudocode:
LatLngBounds.Builder builder = new LatLngBounds.Builder();
while(data) {
LatLng latlng = getPosition();
builder.include(latlng);
}
CameraUpdate cameraUpdate = CameraUpdateFactory
.newLatLngBounds(builder.build(), 10);
map.moveCamera(cameraUpdate);
Der Aufruf von führt dazu, map.moveCamera()
dass meine Anwendung mit dem folgenden Stapel abstürzt:
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)
Wenn - anstelle der newLatLngBounds()
Factory-Methode die Methode verwendet newLatLngZoom()
wird, tritt nicht dieselbe Falle auf.
Ist der onResume
beste Ort, um die Markierungen auf das GoogleMap-Objekt zu zeichnen, oder sollte ich die Markierungen zeichnen und die Kameraposition woanders einstellen?
setOnCameraChangeListener
ist jetzt veraltetDiese Antworten sind in Ordnung, aber ich würde einen anderen Ansatz wählen, einen einfacheren. Wenn die Methode erst funktioniert, nachdem die Karte angelegt wurde, warten Sie einfach darauf:
quelle
OK, ich habe das herausgefunden. Wie hier dokumentiert , kann die API nicht vor dem Layout verwendet werden.
Die richtige API wird wie folgt beschrieben:
Um das Problem zu beheben, habe ich meine Bildschirmgröße berechnet und die Breite und Höhe angegeben
Dadurch konnte ich das Begrenzungsrahmen-Vorlayout festlegen.
quelle
Die Lösung ist einfacher als das ....
Fangen Sie
IllegalStateException
stattdessen den globalen Listener für die Ansicht ab und verwenden Sie ihn. Wenn Sie die gebundene Größe im Voraus (Vorlayout) mit den anderen Methoden einstellen, müssen Sie die Größe von THE VIEW und nicht des Bildschirmgeräts berechnen. Sie stimmen nur überein, wenn Sie mit Ihrer Karte im Vollbildmodus arbeiten und keine Fragmente verwenden.quelle
Dies ist mein Fix, warten Sie einfach, bis die Karte in diesem Fall geladen ist.
quelle
Das Hinzufügen und Entfernen von Markierungen kann vor Abschluss des Layouts erfolgen, das Bewegen der Kamera jedoch nicht (außer
newLatLngBounds(boundary, padding)
wie in der Antwort des OP angegeben).Der wahrscheinlich beste Ort, um ein erstes Kamera-Update durchzuführen, ist die Verwendung einer einmaligen Aufnahme,
OnGlobalLayoutListener
wie im Beispielcode von Google gezeigt. Beispiel: Siehe folgenden AuszugsetUpMap()
in MarkerDemoActivity.java :quelle
Die akzeptierte Antwort würde für mich nicht funktionieren, da ich an verschiedenen Stellen meiner App denselben Code verwenden musste.
Anstatt darauf zu warten, dass sich die Kamera ändert, habe ich eine einfache Lösung erstellt, die auf Lees Vorschlag basiert, die Kartengröße anzugeben. Dies ist der Fall, wenn Ihre Karte die Größe des Bildschirms hat.
Hoffe es hilft jemand anderem!
quelle
Die akzeptierte Antwort ist, wie in den Kommentaren ausgeführt, etwas hackig. Nach der Implementierung habe ich eine überdurchschnittliche Anzahl von
IllegalStateException
Protokollen in Analytics festgestellt . Die Lösung, die ich verwendet habe, besteht darin, eine hinzuzufügen,OnMapLoadedCallback
in der das ausgeführtCameraUpdate
wird. Der Rückruf wird dem hinzugefügtGoogleMap
. Nachdem Ihre Karte vollständig geladen wurde, wird das Kamera-Update durchgeführt.Dies führt dazu, dass auf der Karte kurz die verkleinerte Ansicht (0,0) angezeigt wird, bevor die Kamera aktualisiert wird. Ich bin der Meinung, dass dies akzeptabler ist, als Abstürze zu verursachen oder sich auf undokumentiertes Verhalten zu verlassen.
quelle
Verwenden Sie dies, es hat für mich funktioniert
quelle
In sehr seltenen Fällen ist das MapView-Layout fertig, aber das GoogleMap-Layout ist noch nicht fertig.
ViewTreeObserver.OnGlobalLayoutListener
Der Absturz kann selbst nicht gestoppt werden. Ich habe den Absturz mit der Google Play-Dienstpaketversion 5084032 gesehen. Dieser seltene Fall kann durch die dynamische Änderung der Sichtbarkeit meiner MapView verursacht werden.Um dieses Problem zu lösen, habe ich eingebettet
GoogleMap.OnMapLoadedCallback
inonGlobalLayout()
:quelle
mapView.getViewTreeObserver()
eine lokale Variable umgestalte, tritt der folgende Fehler auf: "IllegalStateException: Dieser ViewTreeObserver ist nicht aktiv, rufen Sie getViewTreeObserver () erneut auf" . Hast du das versucht?Ich habe einen anderen Ansatz verwendet, der für neuere Versionen von Google Maps SDK (9.6+) funktioniert und auf onCameraIdleListener basiert . Wie ich bisher sehe, wird die Rückrufmethode
onCameraIdle
immer danach aufgerufenonMapReady
. Mein Ansatz sieht also wie dieser Code aus (wenn man bedenkt, dass er eingegeben wurdeActivity
):quelle
Ich habe eine Möglichkeit geschaffen, die beiden Rückrufe zu kombinieren: onMapReady und onGlobalLayout in einem einzigen Observable, das nur ausgegeben wird, wenn beide Ereignisse ausgelöst wurden.
https://gist.github.com/abhaysood/e275b3d0937f297980d14b439a8e0d4a
quelle
Ok, ich stehe vor dem gleichen Problem. Ich habe mein Fragment mit meiner SupportmapFragment-, ABS- und Navigationsschublade. Was ich getan habe war:
Und, nebenbei bemerkt , ich rufe
resetCamera()
ausonCreateView
nach dem Aufblasen und vor der Rückkehr.Dies fängt die Ausnahme beim ersten Mal ab (während die Karte "eine Größe bekommt", um es auszudrücken ...) und dann, wenn ich die Kamera zurücksetzen muss, hat die Karte bereits die Größe und führt sie durch Auffüllen aus.
Problem wird in erklärt Dokumentation , heißt es:
Ich denke, es ist eine ziemlich anständige Lösung. Hoffe es hilft jemandem.
quelle
newLatLngBounds()
oder inanimateCamera()
oder in beiden ausgelöst? Wird der Fangzweig nicht zu einer neuen Ausnahme führen?Wenn Sie auf den Start möglicher Benutzerinteraktionen warten müssen, verwenden Sie diese
OnMapLoadedCallback
wie in den vorherigen Antworten beschrieben. Wenn Sie jedoch nur einen Standardspeicherort für die Karte angeben müssen, ist keine der in diesen Antworten beschriebenen Lösungen erforderlich. BeideMapFragment
undMapView
können einenGoogleMapOptions
Start akzeptieren , der den Standardspeicherort in Ordnung liefern kann. Der einzige Trick besteht darin, sie nicht direkt in Ihr Layout aufzunehmen, da das System sie dann ohne die Optionen aufruft, sondern sie dynamisch initialisiert.Verwenden Sie dies in Ihrem Layout:
und ersetzen Sie das Fragment in Ihrem
onCreateView()
:Abgesehen davon, dass der Start schneller ist, wird zuerst keine Weltkarte angezeigt und dann wird eine Kamera bewegt. Die Karte beginnt direkt mit dem angegebenen Ort.
quelle
Ein anderer Ansatz wäre ungefähr so: (Angenommen, Ihre oberste Ansicht ist ein FrameLayout mit dem Namen
rootContainer
, obwohl dies funktioniert, solange Sie immer Ihren obersten Container auswählen, unabhängig davon, welchen Typ oder Namen er hat):Wenn Sie Ihre Kamerafunktionen so ändern, dass sie nur funktionieren, wenn dies der Fall
layoutDone
ist,true
werden alle Ihre Probleme gelöst, ohne dass demlayoutListener
Handler zusätzliche Funktionen hinzugefügt oder Logik verkabelt werden müssen.quelle
Ich fand, dass dies funktioniert und einfacher ist als die anderen Lösungen:
Dadurch wird der Aufruf erneut ausgeführt, nachdem das Layout ausgeführt wurde. Könnte wahrscheinlich eine Sicherheit beinhalten, um eine Endlosschleife zu vermeiden.
quelle
Warum nicht einfach so etwas verwenden:
quelle
newLatLngBounds(builder.build(), padding)
ist nicht drin Try-Catch? Tritt diese Ausnahme in aufmoveCamera()
?Im Google Maps-Repo gibt es eine Hilfsklasse, die Sie nutzen können. Sie wartet darauf, dass sowohl das Layout als auch die Karte fertig sind, bevor Sie einen Rückruf mit GoogleMap benachrichtigen:
Die Originalquelle ist hier:
https://github.com/googlemaps/android-samples/blob/7ee737b8fd6d39c77f8b3716ba948e1ce3730e61/ApiDemos/java/app/src/main/java/com/example/mapdemo/OnMapAndViewReady
Es gibt auch eine Kotlin-Implementierung:
https://github.com/googlemaps/android-samples/blob/master/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
quelle
Wie in OnCameraChangeListener () angegeben, ist es veraltet und
setOnCameraChangeListener
jetzt veraltet. Sie sollten es also durch eine von drei Methoden ersetzen:GoogleMap.OnCameraMoveStartedListener
GoogleMap.OnCameraMoveListener
GoogleMap.OnCameraIdleListener
In meinem Fall habe ich es benutzt
OnCameraIdleListener
und innen entfernt, weil es bei jeder Bewegung immer wieder aufgerufen wurde.AKTUALISIEREN
Ich habe
googleMap.setOnCameraIdleListener
in meinem Projekt entfernt, weil es manchmal nicht aufgerufen wurde, wenn eine Karte angezeigt wurde, sondern beibehalten wurdegoogleMap.setOnCameraIdleListener(clusterManager)
.quelle
Ich hatte den gleichen Fehler beim Versuch, mMap.animateCamera aufzurufen. Ich habe es gelöst, indem ich setOnMapLoadedCallback- Rückruf in meiner onMapReady- Funktion aufgerufen habe , wie unten gezeigt
Dies sollte gut funktionieren.
quelle