Estou usando a nova API do Google Maps para Android .
Eu crio uma atividade que inclui um MapFragment. Na atividade onResume
, defino os marcadores no objeto GoogleMap e, em seguida, defino uma caixa delimitadora para o mapa que inclui todos os marcadores.
Isso está usando o seguinte pseudocó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);
A chamada para map.moveCamera()
faz com que meu aplicativo trave com a seguinte pilha:
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 - em vez do newLatLngBounds()
método de fábrica, eu usar o newLatLngZoom()
método, a mesma armadilha não ocorrerá.
É o onResume
melhor lugar para desenhar os marcadores no objeto GoogleMap ou devo desenhar os marcadores e definir a posição da câmera em outro lugar?
setOnCameraChangeListener
agora está obsoletoEssas respostas são boas, mas eu escolheria uma abordagem diferente, mais simples. Se o método só funcionar depois que o mapa for traçado, espere por ele:
fonte
OK, eu resolvi isso. Conforme documentado aqui, essa API não pode ser usada no pré-layout.
A API correta a ser usada é descrita como:
Para resolver o problema, calculei o tamanho da minha tela e forneci a largura e a altura para
Isso me permitiu especificar o pré-layout da caixa delimitadora.
fonte
A solução é mais simples do que isso ....
Capture
IllegalStateException
e use o ouvinte global na visualização. Definir o tamanho do limite com antecedência (pré-layout) usando os outros métodos significa que você tem que calcular o tamanho de THE VIEW, não o dispositivo de tela. Eles só combinam se você usar o mapa em tela cheia e não usar fragmentos.fonte
Esta é a minha solução, apenas espere até que o mapa seja carregado nesse caso.
fonte
Adicionar e remover marcadores pode ser feito antes da conclusão do layout, mas mover a câmera não pode (exceto usando
newLatLngBounds(boundary, padding)
conforme observado na resposta do OP).Provavelmente o melhor lugar para realizar uma atualização inicial câmera estiver usando uma one-shot
OnGlobalLayoutListener
como mostra a código de exemplo do Google , por exemplo, consulte o seguinte excertosetUpMap()
no MarkerDemoActivity.java :fonte
A resposta aceita não funcionaria para mim porque tive que usar o mesmo código em vários locais do meu aplicativo.
Em vez de esperar a mudança da câmera, criei uma solução simples com base na sugestão de Lee de especificar o tamanho do mapa. Isso ocorre no caso de seu mapa ter o tamanho da tela.
Espero que isso ajude mais alguém!
fonte
A resposta aceita é, como apontado nos comentários, um pouco hacky. Depois de implementá-lo, percebi uma quantidade de
IllegalStateException
logs acima do aceitável em análises. A solução que usei é adicionar umOnMapLoadedCallback
no qual oCameraUpdate
é executado. O retorno de chamada é adicionado aoGoogleMap
. Depois que seu mapa carregar totalmente, a atualização da câmera será realizada.Isso faz com que o mapa mostre brevemente a visualização reduzida (0,0) antes de realizar a atualização da câmera. Eu sinto que isso é mais aceitável do que causar travamentos ou depender de um comportamento não documentado.
fonte
use isso funcionou para mim
fonte
Em casos muito raros, o layout MapView está concluído, mas o layout GoogleMap não está concluído, por
ViewTreeObserver.OnGlobalLayoutListener
si só não consegue parar a falha. Eu vi o travamento com o pacote de serviços do Google Play versão 5084032. Este caso raro pode ser causado pela mudança dinâmica da visibilidade do meu MapView.Para resolver este problema, eu incorporado
GoogleMap.OnMapLoadedCallback
emonGlobalLayout()
,fonte
mapView.getViewTreeObserver()
em uma variável local, ocorre o seguinte erro : "IllegalStateException: Este ViewTreeObserver não está ativo, chame getViewTreeObserver () novamente" . Você tentou isso?Usei uma abordagem diferente que funciona para versões recentes do SDK do Google Maps (9.6+) e com base em onCameraIdleListener . Como vi até agora, é o método de retorno de
onCameraIdle
chamada sempre chamado depoisonMapReady
. Portanto, minha abordagem se parece com este pedaço de código (considerando-o inseridoActivity
):fonte
Eu criei uma maneira de combinar os dois retornos de chamada: onMapReady e onGlobalLayout em um único observável que emitirá apenas quando ambos os eventos forem disparados.
https://gist.github.com/abhaysood/e275b3d0937f297980d14b439a8e0d4a
fonte
Ok, estou enfrentando o mesmo problema. Eu tenho meu fragmento com meu SupportmapFragment, ABS e gaveta de navegação. O que eu fiz foi:
E, a propósito, eu estou chamando
resetCamera()
a partir deonCreateView
depois de inflar e antes de retornar.O que isso faz é pegar a exceção na primeira vez (enquanto map "pega um tamanho" como forma de dizer ...) e depois, outras vezes preciso zerar a câmera, map já tem tamanho e faz através do padding.
O problema é explicado na documentação , que diz:
Acho que é uma solução bastante decente. Espero que ajude alguém.
fonte
newLatLngBounds()
ou emanimateCamera()
, ou em ambos? O catch-branch não levará a uma nova exceção?Se você precisar aguardar o início de possíveis interações do usuário, use
OnMapLoadedCallback
conforme descrito nas respostas anteriores. Mas, se tudo o que você precisa é fornecer um local padrão para o mapa, não há necessidade de nenhuma das soluções descritas nessas respostas. AmbosMapFragment
eMapView
podem aceitar umGoogleMapOptions
no início que pode fornecer o local padrão sem problemas. O único truque é não incluí-los diretamente em seu layout, porque o sistema os chamará sem as opções, mas para inicializá-los dinamicamente.Use isso em seu layout:
e substitua o fragmento em seu
onCreateView()
:Além de ser mais rápido para começar, não haverá um mapa mundial mostrado primeiro e uma câmera se moverá em segundo lugar. O mapa começará diretamente com o local especificado.
fonte
Outra abordagem seria algo como (presumindo que sua visualização superior seja um FrameLayout nomeado
rootContainer
, mesmo que funcione, desde que você sempre escolha seu contêiner superior, não importa o tipo ou nome que ele tenha):Modificando as funções da câmera para funcionar apenas se
layoutDone
étrue
vai resolver todos os seus problemas sem ter que adicionar funções extras ou um fio de lógica para olayoutListener
manipulador.fonte
Achei que isso funcionava e era mais simples do que as outras soluções:
Isso tenta a chamada novamente após a execução do layout. Provavelmente poderia incluir uma segurança para evitar um loop infinito.
fonte
Por que não usar algo assim:
fonte
newLatLngBounds(builder.build(), padding)
não está dentro do try-catch? Essa exceção ocorre emmoveCamera()
?Há uma classe auxiliar no repositório do Google Maps que você pode aproveitar - ela espera que o layout e o mapa estejam prontos antes de notificar um retorno de chamada com o GoogleMap:
A fonte original está aqui:
https://github.com/googlemaps/android-samples/blob/7ee737b8fd6d39c77f8b3716ba948e1ce3730e61/ApiDemos/java/app/src/main/java/com/example/mapdemo/OnMapAndViewReadyListener.java
Também existe uma implementação Kotlin:
https://github.com/googlemaps/android-samples/blob/master/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
fonte
Conforme declarado em OnCameraChangeListener () está obsoleto ,
setOnCameraChangeListener
agora está obsoleto. Portanto, você deve substituí-lo por um dos três métodos:GoogleMap.OnCameraMoveStartedListener
GoogleMap.OnCameraMoveListener
GoogleMap.OnCameraIdleListener
No meu caso, usei
OnCameraIdleListener
e removi por dentro porque era invocado repetidamente em qualquer movimento.ATUALIZAR
Removi
googleMap.setOnCameraIdleListener
no meu projeto, porque às vezes não era chamado quando um mapa era mostrado, mas retidogoogleMap.setOnCameraIdleListener(clusterManager)
.fonte
Eu tive o mesmo erro ao tentar chamar mMap.animateCamera. Eu resolvi chamando setOnMapLoadedCallback callback em minha função onMapReady , conforme mostrado abaixo
Isso deve funcionar bem.
fonte