moveCamera dengan CameraUpdateFactory.newLatLngBounds mogok

96

Saya menggunakan API Google Maps Android baru .

Saya membuat aktivitas yang menyertakan MapFragment. Dalam aktivitas, onResumesaya mengatur penanda ke dalam objek GoogleMap dan kemudian menentukan kotak pembatas untuk peta yang mencakup semua penanda.

Ini menggunakan kode semu berikut:

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

Panggilan tersebut map.moveCamera()menyebabkan aplikasi saya macet dengan tumpukan berikut:

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)

Jika - alih-alih newLatLngBounds()metode pabrik, saya menggunakan newLatLngZoom()metode maka jebakan yang sama tidak terjadi.

Apakah tempat onResumeterbaik untuk menggambar penanda ke objek GoogleMap atau haruskah saya menggambar penanda dan menyetel posisi kamera di tempat lain?

Lee
sumber

Jawaban:

133

Anda dapat menggunakan metode newLatLngBounds sederhana di OnCameraChangeListener . Semua akan bekerja dengan sempurna dan Anda tidak perlu menghitung ukuran layar. Peristiwa ini terjadi setelah perhitungan ukuran peta (seperti yang saya mengerti).

Contoh:

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);
    }
});
Paul Annekov
sumber
1
Ini berfungsi karena setOnCameraChangeListener dijamin berjalan setidaknya sekali, setelah Peta mengalami tata letak? Apakah ini bukti masa depan?
Glenn Bech
3
@SteelRat Itulah mengapa saya menentang penggunaan solusi. Anda tidak pernah tahu kapan Google mengubah ini, atau bahkan jika berfungsi seperti itu di semua versi atau perangkat Android.
Glenn Bech
1
@SteelRat Saya setuju, tetapi mungkin dipanggil lebih dari sekali selama masa aktivitas? Saya hanya membuat argumen bahwa meskipun berhasil dalam kasus ini, ini bukanlah solusi yang sangat elegan. Menurut saya, OnGlobalLayoutListener / Treelistener adalah cara yang lebih tepat untuk melakukannya.
Glenn Bech
4
mungkin menambahkan map.moveCamera (CameraUpdateFactory.scrollBy (1, 1)); setelah kode diatas akan bikin trik?
SAYA
3
setOnCameraChangeListenersekarang tidak digunakan lagi
osrl
56

Jawaban tersebut baik-baik saja, tetapi saya akan menggunakan pendekatan yang berbeda, yang lebih sederhana. Jika metode ini hanya berfungsi setelah peta ditata, tunggu saja:

map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
    @Override
    public void onMapLoaded() {
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30));
    }
});
Leandro
sumber
1
Saya menemukan setelah banyak percobaan bahwa saya perlu menerapkan kombinasi jawaban ini dan Daniele di atas. Terkadang peta belum dimuat, terkadang tata letak belum selesai. Saya tidak bisa menggerakkan kamera sesuai keinginan sampai KEDUA itu terjadi.
RobP
2
Peringatan untuk metode ini, dari dokumen: "Peristiwa ini tidak akan aktif jika peta tidak pernah memuat karena masalah konektivitas, atau jika peta terus berubah dan tidak pernah selesai memuat karena pengguna terus-menerus berinteraksi dengan peta ." (penekanan saya).
stkent
1
Penundaan ini lebih lama dari yang diperlukan karena menunggu petak peta dimuat di posisi yang salah sebelum pindah ke posisi yang benar.
John Patterson
1
Sebagian besar waktu yang dibutuhkan antara 3-10 detik untuk menembak yang tidak dapat diterima.
Nima G
Ini adalah tempat untuk memindahkan kamera. Saya akan menyarankan menggunakan map.animateCamera daripada map.moveCamera
Bharat Dodeja
51

OK saya mengerjakan ini. Seperti yang didokumentasikan di sini bahwa API tidak dapat digunakan sebelum tata letak.

API yang benar untuk digunakan dijelaskan sebagai:

Catatan: Hanya gunakan metode newLatLngBounds (batas, pengisi) yang lebih sederhana untuk membuat CameraUpdate jika itu akan digunakan untuk menggerakkan kamera setelah peta menjalani tata letak. Selama tata letak, API menghitung batas tampilan peta yang diperlukan untuk memproyeksikan kotak pembatas dengan benar. Sebagai perbandingan, Anda bisa menggunakan CameraUpdate yang dikembalikan dengan metode yang lebih kompleks newLatLngBounds (batas, lebar, tinggi, padding) kapan saja, bahkan sebelum peta menjalani tata letak, karena API menghitung batas tampilan dari argumen yang Anda teruskan.

Untuk memperbaiki masalah, saya menghitung ukuran layar saya dan memberikan lebar dan tinggi

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

Ini kemudian memungkinkan saya untuk menentukan tata letak kotak pembatas.

Lee
sumber
18
Tetapi bagaimana jika peta tidak memenuhi seluruh layar?
theblang
Dalam kasus saya, saya hanya mengasumsikan layar lebih besar daripada yang berlaku, dan perlu menghitung padding dengan lebih hati-hati sehingga sebenarnya tidak terlalu besar. Alasan yang jauh lebih sederhana.
rfay
2
Dapatkah Anda menunjukkan cara menghitungnya berdasarkan ukuran layar?
Daniel Gomez Rico
Ini tidak menabrak tetapi lebar dan tinggi yang akan digunakan mendekati tebakan murni, area persis yang akan digambar benar-benar tidak dapat diprediksi.
Vince
34

Solusinya lebih sederhana dari itu ....

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

Tangkap IllegalStateExceptiondan gunakan pendengar global pada tampilan sebagai gantinya. Menetapkan ukuran terikat terlebih dahulu (pra-tata letak) menggunakan metode lain berarti Anda harus menghitung ukuran PANDANGAN, bukan perangkat layar. Mereka hanya cocok jika Anda pergi layar penuh dengan peta Anda dan tidak menggunakan fragmen.

Daniele Segato
sumber
Sampai sekarang saya telah menggunakan potongan kecil Anda, tetapi masih gagal ... jawaban yang benar adalah yang pertama :-)
cesards
1
Bagaimana / kapan gagal? tidak pernah punya masalah dengan ini. Jawaban pertama hanya meneruskan ukuran hardcode sebagai fallback. "Ia bekerja" seperti dalam "ia tidak macet lagi" tetapi ia tidak melakukan hal yang sama.
Daniele Segato
@ andrea.spot Saya tidak ingat mengapa saya mengatakan lebih sederhana. Saya kira solusi yang diterima telah diedit sementara itu. The saat ini solusi yang diterima menganggap peta Anda mengambil semua layar, yang tidak selalu benar. Jika Anda tidak termasuk dalam kasus itu, Anda perlu mengetahui ukuran peta atau menggunakan metode saya atau yang serupa.
Daniele Segato
periksa juga jawaban di bawah ini oleh Xingang Huang, itu menambahkan sedikit.
Daniele Segato
15

Ini perbaikan saya, tunggu saja sampai peta dimuat dalam kasus itu.

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
sumber
Sederhana dan efisien +1
Shid
14

Menambah dan menghapus penanda dapat dilakukan penyelesaian pra-tata letak, tetapi menggerakkan kamera tidak bisa (kecuali menggunakan newLatLngBounds(boundary, padding)seperti yang disebutkan dalam jawaban OP).

Mungkin tempat terbaik untuk melakukan pembaruan kamera awal adalah menggunakan satu jepretan OnGlobalLayoutListenerseperti yang ditunjukkan dalam kode contoh Google , misalnya lihat kutipan berikut dari setUpMap()di 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));
        }
    });
}
StephenT
sumber
Saya mendapatkan kesalahan ini pada perubahan orientasi. Saya juga menemukan ini dari kode sampel tetapi ini tidak berhasil untuk saya. Saya tetap mengalami masalah yang sama.
osrl
14

Jawaban yang diterima tidak akan berfungsi untuk saya karena saya harus menggunakan kode yang sama di berbagai tempat aplikasi saya.

Alih-alih menunggu kamera berubah, saya membuat solusi sederhana berdasarkan saran Lee untuk menentukan ukuran peta. Ini seandainya peta Anda berukuran layar.

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

Semoga bisa membantu orang lain!

Teo Inke
sumber
8

Jawaban yang diterima, seperti yang ditunjukkan di komentar, sedikit hacky. Setelah menerapkannya, saya melihat jumlah IllegalStateExceptionlog di analytics yang dapat diterima di atas. Solusi yang saya gunakan adalah menambahkan OnMapLoadedCallbackdi mana CameraUpdatedilakukan. Callback ditambahkan ke GoogleMap. Setelah peta Anda dimuat sepenuhnya, pembaruan kamera akan dilakukan.

Hal ini menyebabkan peta secara singkat menunjukkan tampilan yang diperkecil (0,0) sebelum melakukan pembaruan kamera. Saya merasa ini lebih dapat diterima daripada menyebabkan crash atau mengandalkan perilaku yang tidak terdokumentasi.

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

gunakan ini, itu berhasil untukku

Ramesh Bhupathi
sumber
Ini hanya memusatkan peta tetapi tidak secara dinamis menyesuaikan zoom ke batas.
Giovanni Di Gregorio
Kami dapat menghitung batas untuk lebih banyak matker menggunakan "LatLngBounds.Builder".
Ramesh Bhupathi
@RameshBhupathi tetapi itu akan tetap menjadi tampilan peta dengan pusat dan zoom.
Tima
4

Dalam kasus yang sangat jarang terjadi, tata letak MapView selesai, tetapi tata letak GoogleMap belum selesai, ViewTreeObserver.OnGlobalLayoutListeneritu sendiri tidak dapat menghentikan kerusakan. Saya melihat crash dengan paket layanan Google Play versi 5084032. Kasus yang jarang terjadi ini mungkin disebabkan oleh perubahan dinamis pada visibilitas MapView saya.

Untuk mengatasi masalah ini, saya tertanam GoogleMap.OnMapLoadedCallbackdi 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));
                    }
                });
            }
        }
    });
}
Alpha Huang
sumber
Menarik: Jika saya melakukan refactor mapView.getViewTreeObserver()menjadi variabel lokal , kesalahan berikut terjadi: "IllegalStateException: ViewTreeObserver ini tidak hidup, panggil getViewTreeObserver () lagi" . Apakah kamu sudah mencobanya?
JJD
Jika mapView.getViewTreeObserver (). IsAlive () kebetulan salah, saya akan menempatkan satu fallback lagi untuk map.setOnMapLoadedCallback ()
southerton
4

Saya menggunakan pendekatan berbeda yang berfungsi untuk versi terbaru Google Maps SDK (9.6+) dan berdasarkan onCameraIdleListener . Seperti yang saya lihat sejauh ini, metode callback onCameraIdleselalu dipanggil setelah onMapReady. Jadi pendekatan saya terlihat seperti potongan kode ini (mengingatnya dimasukkan 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
    */
}
Viacheslav
sumber
4

Saya telah membuat cara untuk menggabungkan dua callback: onMapReady dan onGlobalLayout menjadi satu observable tunggal yang akan memancarkan hanya ketika kedua peristiwa telah dipicu.

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

Abhay Sood
sumber
1
Ini sebenarnya cara terbersih untuk mengatasi ini. Saya melakukan ini untuk waktu yang lama sekarang dan tidak ada kesalahan yang dikembalikan dalam analitik bahkan pada 1k pengguna per aplikasi hari. +1
Skyle
2

Oke, saya menghadapi masalah yang sama. Saya memiliki fragmen saya dengan SupportmapFragment, ABS, dan laci navigasi saya. Apa yang saya lakukan adalah:

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

Dan, omong-omong, saya menelepon resetCamera()dari onCreateViewsetelah menggembungkan dan sebelum kembali.
Apa yang dilakukan ini adalah menangkap pengecualian pertama kali (sementara peta "mendapat ukuran" sebagai cara untuk mengatakannya ...) dan kemudian, di lain waktu saya perlu mengatur ulang kamera, peta sudah memiliki ukuran dan melakukannya melalui bantalan.

Masalah dijelaskan dalam dokumentasi , dikatakan:

Jangan ubah kamera dengan pembaruan kamera ini hingga peta menjalani tata letak (agar metode ini dapat menentukan kotak pembatas dan tingkat zoom yang sesuai, peta harus memiliki ukuran). Jika tidak, IllegalStateExceptionkeinginan akan terlempar. Tidaklah cukup jika peta tersedia (yaitu getMap()mengembalikan objek bukan null); tampilan yang berisi peta juga harus menjalani tata letak sedemikian rupa sehingga dimensinya telah ditentukan. Jika Anda tidak dapat memastikan bahwa ini telah terjadi, gunakan newLatLngBounds(LatLngBounds, int, int, int)dan berikan dimensi peta secara manual.

Saya pikir ini solusi yang cukup baik. Semoga bisa membantu seseorang.

unmultimedio
sumber
1
apakah ada pendengar untuk mendengarkan saat tata letak dimuat sepenuhnya. ?
Sagar Nayak
Apakah pengecualian dimunculkan di newLatLngBounds()atau di animateCamera(), atau di keduanya? Apakah cabang penangkap tidak akan menghasilkan pengecualian baru?
CoolMind
1

Jika Anda perlu menunggu kemungkinan interaksi pengguna untuk dimulai, gunakan OnMapLoadedCallbackseperti yang dijelaskan dalam jawaban sebelumnya. Namun, jika yang Anda butuhkan hanyalah memberikan lokasi default untuk peta, tidak perlu solusi apa pun yang diuraikan dalam jawaban tersebut. Keduanya MapFragmentdan MapViewdapat menerima GoogleMapOptionsdi awal yang dapat memberikan lokasi default dengan baik. Trik satu-satunya adalah dengan tidak menyertakannya secara langsung dalam tata letak Anda karena sistem akan memanggilnya tanpa opsi, tetapi menginisialisasinya secara dinamis.

Gunakan ini dalam tata letak Anda:

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

dan ganti fragmen di 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();

Selain lebih cepat untuk memulai, tidak akan ada peta dunia yang ditampilkan pertama dan kamera bergerak kedua. Peta akan langsung dimulai dengan lokasi yang ditentukan.

Gábor
sumber
0

Pendekatan lain akan seperti ini (Dengan asumsi tampilan teratas Anda adalah FrameLayout bernama rootContainer, meskipun itu akan berfungsi selama Anda selalu memilih penampung teratas Anda tidak peduli jenis atau nama yang dimilikinya):

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

Memodifikasi fungsi kamera Anda agar hanya berfungsi jika layoutDoneada trueakan menyelesaikan semua masalah Anda tanpa harus menambahkan fungsi tambahan atau menghubungkan logika ke layoutListenerpawang.

Machinarius
sumber
0

Saya menemukan ini berfungsi dan menjadi lebih sederhana daripada solusi lain:

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

Ini mencoba panggilan lagi setelah layout dijalankan. Mungkin bisa termasuk pengaman untuk menghindari loop tak terbatas.

John Patterson
sumber
0

Mengapa tidak menggunakan sesuatu seperti ini:

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);
}
Hristo Lalev
sumber
Mengapa newLatLngBounds(builder.build(), padding)tidak di dalam coba-tangkap? Apakah pengecualian ini terjadi di moveCamera()?
CoolMind
0

Ada kelas pembantu di repo Google Maps yang dapat Anda manfaatkan - kelas itu menunggu tata letak dan peta siap sebelum memberi tahu panggilan balik dengan GoogleMap:

Sumber aslinya ada di sini:

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

Ada juga implementasi 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
sumber
0

Seperti yang dinyatakan di OnCameraChangeListener () tidak digunakan lagi , setOnCameraChangeListenersekarang tidak digunakan lagi. Jadi, Anda harus menggantinya dengan salah satu dari tiga mode:

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

Dalam kasus saya, saya menggunakan OnCameraIdleListenerdan di dalam saya menghapusnya karena itu dipanggil lagi dan lagi pada setiap gerakan.

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

MEMPERBARUI

Saya menghapus googleMap.setOnCameraIdleListenerdalam proyek saya, karena kadang-kadang tidak dipanggil ketika peta ditampilkan, tetapi dipertahankan googleMap.setOnCameraIdleListener(clusterManager).

CoolMind
sumber
terima kasih atas balasan Anda. Saya sudah menemukan solusi yang hampir sama seperti ini.
Arslan Maqbool
@ArslanMaqbool, terima kasih! Saya sedang dalam proses sekarang dan akan berterima kasih kepada Anda jika Anda membagikan varian Anda.
CoolMind
kesenangan saya @CoolMind
Arslan Maqbool
0

Saya mengalami kesalahan yang sama saat mencoba memanggil mMap.animateCamera. Saya menyelesaikannya dengan memanggil callback setOnMapLoadedCallback dalam fungsi onMapReady saya seperti yang ditunjukkan di bawah ini

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

   // other codes go there

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

Ini seharusnya bekerja dengan baik.

Paul Kumchi
sumber