moveCamera com CameraUpdateFactory.newLatLngBounds trava


96

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 onResumemelhor lugar para desenhar os marcadores no objeto GoogleMap ou devo desenhar os marcadores e definir a posição da câmera em outro lugar?

Respostas:


133

Você pode usar o método newLatLngBounds simples em OnCameraChangeListener . Tudo funcionará perfeitamente e você não precisa calcular o tamanho da tela. Este evento ocorre após o cálculo do tamanho do mapa (pelo que entendi).

Exemplo:

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
Isso funciona porque setOnCameraChangeListener tem garantia de execução pelo menos uma vez, depois que o mapa foi submetido ao layout? Isso é à prova de futuro?
Glenn Bech

3
@SteelRat É por isso que eu seria contra o uso da solução. Você nunca sabe quando o Google muda isso, ou mesmo se funciona dessa forma em todas as versões ou dispositivos Android.
Glenn Bech

1
@SteelRat Eu concordo, mas pode ser chamado mais de uma vez durante a atividade? Estou apenas argumentando que, mesmo que funcione neste caso, não é uma solução muito elegante. Acho que OnGlobalLayoutListener / Treelistener é a maneira mais correta de fazer isso.
Glenn Bech

4
talvez adicionando map.moveCamera (CameraUpdateFactory.scrollBy (1, 1)); depois que o código acima vai fazer o truque?
MEU

3
setOnCameraChangeListeneragora está obsoleto
osrl

56

Essas 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:

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

1
Depois de muita experimentação, descobri que precisava implementar uma combinação dessa resposta com a de Daniele acima. Às vezes, o mapa ainda não havia sido carregado, às vezes o layout ainda não havia sido concluído. Eu não conseguia mover a câmera como desejado até que AMBOS isso acontecesse.
RobP de

2
Aviso para este método, dos documentos: "Este evento não será disparado se o mapa nunca for carregado devido a problemas de conectividade ou se o mapa estiver mudando continuamente e nunca concluir o carregamento devido à interação constante do usuário com o mapa ." (ênfase minha).
stkent

1
Isso atrasa mais do que o necessário porque espera que os blocos do mapa carreguem na posição errada antes de mover para a posição correta.
John Patterson

1
Na maioria das vezes, leva de 3 a 10 segundos para disparar, o que é inaceitável.
Nima G

Este é o lugar para mover a câmera. Eu sugeriria usar map.animateCamera em vez de map.moveCamera
Bharat Dodeja

51

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:

Nota: Use apenas o método mais simples newLatLngBounds (limite, preenchimento) para gerar uma CameraUpdate se ela for usada para mover a câmera após o mapa ter sido submetido ao layout. Durante o layout, a API calcula os limites de exibição do mapa que são necessários para projetar corretamente a caixa delimitadora. Em comparação, você pode usar o CameraUpdate retornado pelo método mais complexo newLatLngBounds (limite, largura, altura, preenchimento) a qualquer momento, mesmo antes de o mapa sofrer layout, porque a API calcula os limites de exibição a partir dos argumentos que você passa.

Para resolver o problema, calculei o tamanho da minha tela e forneci a largura e a altura para

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

Isso me permitiu especificar o pré-layout da caixa delimitadora.


18
Mas e se o mapa não ocupar a tela inteira?
theblang

No meu caso, presumi uma tela maior do que a que estava em vigor e precisava calcular o preenchimento com mais cuidado para que na verdade não fosse muito grande. Um motivo muito mais simples.
quinta-

2
Você pode mostrar como calculá-lo com base no tamanho da tela?
Daniel Gomez Rico

Isso não trava, mas a largura e a altura a serem usadas são próximas de suposições, a área exata a ser desenhada é realmente imprevisível.
Vince de

34

A solução é mais simples do que isso ....

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

Capture IllegalStateExceptione 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.


Até agora tenho usado seu pequeno trecho, mas ainda falhou ... a resposta correta é a primeira :-)
cesards

1
Como / quando falha? nunca tive um problema com isso. A primeira resposta apenas passa um tamanho codificado para ela como um fallback. "Funciona" como em "não trava mais", mas não está fazendo a mesma coisa.
Daniele Segato,

@ andrea.spot Não me lembro porque disse mais simples. Acho que a solução aceita foi editada entretanto. A solução atualmente aceita pressupõe que seu mapa ocupe toda a tela, o que nem sempre é verdade. Se você não cair nesse caso, você precisa saber o tamanho do mapa ou usar meu método ou algo semelhante.
Daniele Segato

verifique também a resposta abaixo de Xingang Huang, ela acrescenta um pouco.
Daniele Segato

15

Esta é a minha solução, apenas espere até que o mapa seja carregado nesse 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));
        }
    });
}

Simples e eficiente +1
Shid

14

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 OnGlobalLayoutListenercomo mostra a código de exemplo do Google , por exemplo, consulte o seguinte excerto setUpMap()no 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));
        }
    });
}


Recebo este erro na mudança de orientação. Eu também encontrei isso no código de amostra, mas não funcionou para mim. Ainda obtenho o mesmo erro.
osrl

14

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.

// 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 isso ajude mais alguém!


8

A resposta aceita é, como apontado nos comentários, um pouco hacky. Depois de implementá-lo, percebi uma quantidade de IllegalStateExceptionlogs acima do aceitável em análises. A solução que usei é adicionar um OnMapLoadedCallbackno qual o CameraUpdateé executado. O retorno de chamada é adicionado ao GoogleMap. 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.


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

use isso funcionou para mim


Isso apenas centraliza o mapa, mas não ajusta dinamicamente o zoom aos limites.
Giovanni Di Gregorio

Podemos calcular limites para mais matkers usando "LatLngBounds.Builder".
Ramesh Bhupathi

@RameshBhupathi mas continuará a ser uma visualização do mapa com um centro e um zoom.
Tima

4

Em casos muito raros, o layout MapView está concluído, mas o layout GoogleMap não está concluído, por ViewTreeObserver.OnGlobalLayoutListenersi 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.OnMapLoadedCallbackem 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 eu refatorar mapView.getViewTreeObserver()em uma variável local, ocorre o seguinte erro : "IllegalStateException: Este ViewTreeObserver não está ativo, chame getViewTreeObserver () novamente" . Você tentou isso?
JJD

Se mapView.getViewTreeObserver (). IsAlive () for falso, eu colocaria mais um substituto para map.setOnMapLoadedCallback ()
southerton

4

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 onCameraIdlechamada sempre chamado depois onMapReady. Portanto, minha abordagem se parece com este pedaço de código (considerando-o inserido 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

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


1
Na verdade, é a maneira mais limpa de resolver isso. Estou fazendo isso há muito tempo e nenhum erro é retornado na análise, mesmo em 1k usuários por dia de aplicativo. +1
Skyle

2

Ok, estou enfrentando o mesmo problema. Eu tenho meu fragmento com meu SupportmapFragment, ABS e gaveta de navegação. O que eu fiz foi:

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 propósito, eu estou chamando resetCamera()a partir de onCreateViewdepois 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:

Não altere a câmera com esta atualização de câmera até que o mapa tenha sofrido um layout (para que este método determine corretamente a caixa delimitadora e o nível de zoom apropriados, o mapa deve ter um tamanho). Caso contrário, um IllegalStateExceptionserá lançado. NÃO é suficiente que o mapa esteja disponível (ou seja, getMap()retorna um objeto não nulo); a visualização que contém o mapa também deve ter passado por layout de forma que suas dimensões tenham sido determinadas. Se você não tiver certeza de que isso ocorreu, use newLatLngBounds(LatLngBounds, int, int, int)e forneça as dimensões do mapa manualmente.

Acho que é uma solução bastante decente. Espero que ajude alguém.


1
existe algum ouvinte para ouvir quando o layout está totalmente carregado. ?
Sagar Nayak de

A exceção é gerada em newLatLngBounds()ou em animateCamera(), ou em ambos? O catch-branch não levará a uma nova exceção?
CoolMind

1

Se você precisar aguardar o início de possíveis interações do usuário, use OnMapLoadedCallbackconforme 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. Ambos MapFragmente MapViewpodem aceitar um GoogleMapOptionsno 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:

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

e substitua o fragmento em seu 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();

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.


0

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

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

Modificando as funções da câmera para funcionar apenas se layoutDoneé truevai resolver todos os seus problemas sem ter que adicionar funções extras ou um fio de lógica para o layoutListenermanipulador.


0

Achei que isso funcionava e era mais simples do que as outras soluções:

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

Isso tenta a chamada novamente após a execução do layout. Provavelmente poderia incluir uma segurança para evitar um loop infinito.


0

Por que não usar algo assim:

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

Por que newLatLngBounds(builder.build(), padding)não está dentro do try-catch? Essa exceção ocorre em moveCamera()?
CoolMind

0

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

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

Conforme declarado em OnCameraChangeListener () está obsoleto , setOnCameraChangeListeneragora está obsoleto. Portanto, você deve substituí-lo por um dos três métodos:

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

No meu caso, usei OnCameraIdleListenere removi por dentro porque era invocado repetidamente em qualquer 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)
}

ATUALIZAR

Removi googleMap.setOnCameraIdleListenerno meu projeto, porque às vezes não era chamado quando um mapa era mostrado, mas retido googleMap.setOnCameraIdleListener(clusterManager).


obrigado pela sua resposta. Já estou descobrindo uma solução quase igual a esta.
Arslan Maqbool

@ArslanMaqbool, obrigado! Estou em processo agora e serei grato a você se compartilhar sua variante.
CoolMind

o prazer é meu @CoolMind
Arslan Maqbool

0

Eu tive o mesmo erro ao tentar chamar mMap.animateCamera. Eu resolvi chamando setOnMapLoadedCallback callback em minha função onMapReady , conforme mostrado abaixo

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

   // other codes go there

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

Isso deve funcionar bem.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.