moveCamera с CameraUpdateFactory.newLatLngBounds дает сбой

96

Я использую новый Android Google Maps API .

Я создаю действие, которое включает MapFragment. В этом упражнении onResumeя устанавливаю маркеры в объект GoogleMap, а затем определяю ограничивающую рамку для карты, которая включает все маркеры.

Это использует следующий псевдокод:

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

Вызов map.moveCamera()вызывает сбой моего приложения со следующим стеком:

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)

Если - вместо newLatLngBounds()фабричного метода я использую newLatLngZoom()метод, то такой ловушки не возникает.

Является ли onResumeлучшее место , чтобы сделать маркеры на объект GoogleMap или я должен быть рисунок маркеры и настройки положения камеры где - нибудь еще?

Ли
источник

Ответы:

133

Вы можете использовать простой newLatLngBounds метод в OnCameraChangeListener . Все будет работать отлично, и вам не нужно рассчитывать размер экрана. Это событие происходит после расчета размера карты (насколько я понимаю).

Пример:

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
Это работает, потому что setOnCameraChangeListener гарантированно запускается хотя бы один раз после того, как карта подверглась макету? Это доказательство будущего?
Гленн Бек
3
@SteelRat Вот почему я был бы против использования решения. Вы никогда не знаете, когда Google изменит это, или даже если это работает на всех версиях или устройствах Android.
Glenn Bech
1
@SteelRat Я согласен, но он может вызываться более одного раза за время существования активности? Я просто утверждаю, что даже если это сработает в данном случае, это не очень элегантное решение. Я думаю, что OnGlobalLayoutListener / Treelistener - более правильный способ сделать это.
Glenn Bech
4
возможно добавление map.moveCamera (CameraUpdateFactory.scrollBy (1, 1)); после того, как приведенный выше код сделает фокус?
MY
3
setOnCameraChangeListenerустарело
osrl
56

Эти ответы прекрасны, но я бы выбрал другой подход, более простой. Если метод работает только после того, как карта выложена, просто подождите:

map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
    @Override
    public void onMapLoaded() {
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30));
    }
});
Леандро
источник
1
После долгих экспериментов я обнаружил, что мне нужно реализовать комбинацию этого ответа и Даниэля выше. Иногда карта еще не загружена, иногда макет еще не завершен. Я не мог перемещать камеру как хотелось, пока не произошло ОБЕИХ событий.
RobP
2
Предупреждение для этого метода из документации: «Это событие не сработает, если карта никогда не загружается из-за проблем с подключением, или если карта постоянно меняется и никогда не завершает загрузку из-за того, что пользователь постоянно взаимодействует с картой ». (курсив мой).
stkent
1
Это задерживается дольше, чем необходимо, потому что ожидает загрузки фрагментов карты в неправильном положении, прежде чем перейти в правильное положение.
Джон Паттерсон
1
В большинстве случаев для срабатывания требуется от 3 до 10 секунд, что недопустимо.
Nima G
Это место для перемещения камеры. Я бы посоветовал использовать map.animateCamera, а не map.moveCamera
Бхарат Додежа
51

Хорошо, я разобрался с этим. Как описано здесь , API нельзя использовать перед макетом.

Правильный API для использования описывается как:

Примечание. Используйте более простой метод newLatLngBounds (border, padding) для создания CameraUpdate только в том случае, если он будет использоваться для перемещения камеры после того, как карта будет разложена. Во время компоновки API вычисляет границы отображения карты, которые необходимы для правильного проецирования ограничивающей рамки. Для сравнения, вы можете использовать CameraUpdate, возвращаемый более сложным методом newLatLngBounds (граница, ширина, высота, отступ) в любое время, даже до того, как карта подвергнется макету, поскольку API вычисляет границы отображения на основе переданных вами аргументов.

Чтобы решить эту проблему, я рассчитал размер экрана и указал ширину и высоту для

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

Это позволило мне указать предварительный макет ограничивающей рамки.

Ли
источник
18
Но что, если карта не занимает весь экран?
theblang
В моем случае я просто предположил, что экран больше, чем был на самом деле, и мне нужно было более тщательно рассчитать отступы, чтобы на самом деле он не был слишком большим. Причина гораздо более простая.
rfay
2
Можете показать, как его рассчитать исходя из размера экрана?
Daniel Gomez Rico
Это не сбой, но используемые ширина и высота близки к чистым предположениям, точная область, которую нужно нарисовать, действительно непредсказуема.
Винс
34

Решение проще ...

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

Поймайте IllegalStateExceptionи используйте вместо этого глобальный слушатель в представлении. Предварительная установка размера границы (предварительная компоновка) с использованием других методов означает, что вам нужно вычислить размер ВИДА, а не устройства экрана. Они совпадают только в том случае, если вы используете карту в полноэкранном режиме и не используете фрагменты.

Даниэле Сегато
источник
До сих пор я использовал ваш маленький фрагмент, но он все равно терпит неудачу ... правильный ответ - первый :-)
cesards
1
Как / когда это не удается? никогда не имел с этим проблем. Первый ответ просто передайте ему жестко запрограммированный размер в качестве запасного варианта. «Он работает», как «он больше не падает», но это не то же самое.
Даниэле Сегато
@ andrea.spot Не помню, почему я сказал проще. Я предполагаю, что принятое решение тем временем было отредактировано. Ток общепринятый решение Предположим , ваша карта взять все на экран, что не всегда верно. Если вы не упадете в этом случае, вам нужно либо знать размер карты, либо использовать мой метод или что-то подобное.
Даниэле Сегато
также проверьте ответ Xingang Huang ниже, он немного добавляет к нему.
Даниэле Сегато
15

Это мое исправление, просто подождите, пока карта загрузится в этом случае.

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
источник
Просто и эффективно +1
Шид
14

Добавление и удаление маркеров может быть выполнено до завершения макета, но перемещение камеры невозможно (за исключением использования newLatLngBounds(boundary, padding) как указано в ответе OP).

Вероятно, лучшее место для выполнения первоначального обновления камеры - использовать однократный снимок, OnGlobalLayoutListenerкак показано на примере кода от Google , например , см следующего отрывка из setUpMap()в 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));
        }
    });
}
Стивен
источник
Я получаю эту ошибку при изменении ориентации. Я также нашел это в образце кода, но у меня это не сработало. Я все еще получаю ту же ошибку.
osrl
14

Принятый ответ не сработает для меня, потому что мне пришлось использовать один и тот же код в разных местах моего приложения.

Вместо того, чтобы ждать смены камеры, я создал простое решение, основанное на предложении Ли указать размер карты. Это на случай, если ваша карта размером с экран.

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

Надеюсь, это поможет кому-то другому!

Тео Инке
источник
8

Принятый ответ, как указано в комментариях, немного взломан. После внедрения заметил IllegalStateExceptionв аналитике недопустимое количество логов. Решение, которое я использовал, - это добавить объект, OnMapLoadedCallbackв котором CameraUpdateвыполняется. Обратный вызов добавлен в GoogleMap. После полной загрузки карты будет выполнено обновление камеры.

Это заставляет карту ненадолго показывать уменьшенное изображение (0,0) перед выполнением обновления камеры. Я считаю, что это более приемлемо, чем вызывать сбои или полагаться на недокументированное поведение.

пустышка
источник
5
 map.moveCamera(CameraUpdateFactory.newLatLngZoom(bounds.getCenter(),10));

использовать это сработало для меня

Рамеш Бхупати
источник
Это просто центрирует карту, но не динамически регулирует масштаб до границ.
Джованни Ди Грегорио
Мы можем рассчитать границы для большего количества маткеров с помощью LatLngBounds.Builder.
Рамеш Бхупати
@RameshBhupathi, но он по-прежнему останется видом карты с центром и масштабированием.
Tima
4

В очень редких случаях макет MapView завершен, но макет GoogleMap не завершен, ViewTreeObserver.OnGlobalLayoutListenerсам по себе не может остановить сбой. Я видел сбой в пакете сервисов Google Play версии 5084032. Этот редкий случай может быть вызван динамическим изменением видимости моего MapView.

Чтобы решить эту проблему, я встроил GoogleMap.OnMapLoadedCallbackв 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));
                    }
                });
            }
        }
    });
}
Альфа Хуанг
источник
Интересно: Если я рефакторинг mapView.getViewTreeObserver()в локальную переменную следующие ошибки происходит: «IllegalStateException: Это ViewTreeObserver нет в живых, называют getViewTreeObserver () еще раз» . Вы пробовали это?
JJD 06
Если mapView.getViewTreeObserver (). IsAlive () оказывается ложным, я бы добавил еще один запасной вариант для map.setOnMapLoadedCallback ()
southerton
4

Я использовал другой подход, который работает для последних версий Google Maps SDK (9.6+) и основан на onCameraIdleListener . Насколько я понимаю, этот метод обратного вызова onCameraIdleвсегда вызывается после onMapReady. Итак, мой подход выглядит как этот фрагмент кода (учитывая его вставку 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

Я создал способ объединить два обратных вызова: onMapReady и onGlobalLayout в один наблюдаемый объект, который будет генерировать только тогда, когда оба события будут запущены.

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

Абхай Суд
источник
1
Фактически, это самый простой способ решить эту проблему. Я занимаюсь этим уже давно, и в аналитике не выдает ошибок даже на 1к пользователей в день. +1
Skyle
2

Хорошо, у меня такая же проблема. У меня есть фрагмент с моим SupportmapFragment, ABS и навигационным ящиком. Что я сделал:

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

И, кстати, звоню resetCamera()из- onCreateViewза накачки и перед возвращением.
То, что это делает, - это первый раз перехватить исключение (в то время как карта «получает размер» как способ сказать это ...), а затем, в других случаях, когда мне нужно сбросить камеру, карта уже имеет размер и делает это через заполнение.

Проблема объясняется в документации , в ней говорится:

Не меняйте камеру с этим обновлением камеры, пока карта не будет разложена (чтобы этот метод правильно определил соответствующую ограничивающую рамку и уровень масштабирования, карта должна иметь размер). В противном случае IllegalStateExceptionбудет брошено. Недостаточно, чтобы карта была доступна (т. getMap()Е. Возвращала ненулевой объект); вид, содержащий карту, также должен быть подвергнут макету, чтобы были определены его размеры. Если вы не можете быть уверены, что это произошло, используйте newLatLngBounds(LatLngBounds, int, int, int)вместо этого и укажите размеры карты вручную.

Думаю, это довольно приличное решение. Надеюсь, это кому-то поможет.

unmultimedio
источник
1
есть ли какой-нибудь слушатель, чтобы слушать, когда макет полностью загружен. ?
Sagar Nayak
Возникает ли исключение в newLatLngBounds()или в animateCamera(), или в обоих? Не приведет ли перехватчик к новому исключению?
CoolMind
1

Если вам нужно дождаться начала возможного взаимодействия с пользователем, используйте, OnMapLoadedCallbackкак описано в предыдущих ответах. Но если все, что вам нужно, это указать местоположение по умолчанию для карты, нет необходимости в каких-либо решениях, изложенных в этих ответах. Оба MapFragmentи MapViewмогут принять GoogleMapOptionsпри запуске, что может правильно указать местоположение по умолчанию. Единственная уловка - не включать их непосредственно в ваш макет, потому что тогда система будет вызывать их без параметров, а инициализировать их динамически.

Используйте это в своем макете:

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

и замените фрагмент в своем 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();

Помимо более быстрого запуска, сначала не будет отображаться карта мира, а во вторую - движение камеры. Карта начнется напрямую с указанного места.

Габор
источник
0

Другой подход может выглядеть примерно так (при условии, что ваше самое верхнее представление - это FrameLayout с именем rootContainer, даже если оно будет работать, пока вы всегда выбираете свой самый верхний контейнер, независимо от того, какой у него тип или имя):

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

Изменение функций камеры так, чтобы они работали только в том случае, если layoutDoneэто trueрешит все ваши проблемы без добавления дополнительных функций или подключения логики к layoutListenerобработчику.

Machinarius
источник
0

Я обнаружил, что это работает и проще, чем другие решения:

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

Это пытается выполнить вызов еще раз после запуска макета. Возможно, можно было бы включить безопасность, чтобы избежать бесконечного цикла.

Джон Паттерсон
источник
0

Почему бы просто не использовать что-то вроде этого:

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);
}
Христо Лалев
источник
Почему newLatLngBounds(builder.build(), padding)нет внутри try-catch? Возникает ли это исключение в moveCamera()?
CoolMind
0

В репозитории Google Maps есть вспомогательный класс, который вы можете использовать - он ждет, пока макет и карта будут готовы, прежде чем уведомить обратный вызов с помощью GoogleMap:

Первоисточник здесь:

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

Также есть реализация 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
источник
0

Как указано в OnCameraChangeListener () устарел , setOnCameraChangeListenerтеперь он устарел. Поэтому вам следует заменить его одним из трех способов:

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

В моем случае я использовал, OnCameraIdleListenerа внутри я удалил его, потому что он снова и снова вызывается при любом движении.

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

ОБНОВИТЬ

Я удалил googleMap.setOnCameraIdleListenerв своем проекте, потому что он иногда не вызывался при показе карты, но сохранялся googleMap.setOnCameraIdleListener(clusterManager).

CoolMind
источник
Спасибо за ответ. Я уже нашел решение, почти такое же, как это.
Арслан Макбул
@ArslanMaqbool, спасибо! Я сейчас в процессе и буду благодарен вам, если вы поделитесь своим вариантом.
CoolMind
с удовольствием @CoolMind
Арслан Макбул
0

У меня была такая же ошибка при попытке вызвать mMap.animateCamera. Я решил это, вызвав обратный вызов setOnMapLoadedCallback в моей функции onMapReady, как показано ниже.

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

   // other codes go there

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

Это должно работать нормально.

Пол Кумчи
источник