简体   繁体   中英

Google Maps ClusterManager Cluster don't show up on start of the app

I'm using a cluster manager in the google maps app I'm currently developing. My problem is that whenever I start the app on the Android Studio Emulator the clusters won't show up. To make them show up you have to zoom in and out a few times. The clustering itself works fine from this point but it really annoys me that the cluster don't show up initially. Is there a workarround for this or am I doing something wrong in general? I experimented with

clusterManager.cluster()

or

mMap.clear()

but none of that helped me. Maybe one of you can help me:)

Here is the Code from my MapsActivity. I'm using a custom clusterRenderer.

package com.example.multimodaltraffic

import android.os.Bundle
import android.widget.Toast
import androidx.fragment.app.*
import androidx.appcompat.app.AppCompatActivity
import com.example.multimodaltraffic.api.ApiRequests
import com.example.multimodaltraffic.api.stations.NetworkJson
import com.example.multimodaltraffic.locationMarking.MyClusterRenderer
import com.example.multimodaltraffic.locationMarking.MyItem
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.google.maps.android.clustering.ClusterManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import androidx.constraintlayout.widget.ConstraintLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.Retrofit
import retrofit2.awaitResponse
import retrofit2.converter.gson.GsonConverterFactory
import com.example.multimodaltraffic.markerInformationSheet.CustomBottomSheetDialogFragment
import com.example.multimodaltraffic.markerInformationSheet.MyClusterItemClickListener
import com.example.multimodaltraffic.markerInformationSheet.MyClusterClickListener



const val BASE_URL = "https://api.citybik.es"

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mMap: GoogleMap
    private lateinit var clusterManager: ClusterManager<MyItem?>
    private lateinit var myClusterItemClickListener: MyClusterItemClickListener
    private lateinit var myClusterClickListener: MyClusterClickListener
    private lateinit var mapFragment: SupportMapFragment

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_maps)
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        mapFragment = supportFragmentManager
                .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     */
    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap

        // Placeholder for camera start position
        val kassel = LatLng(51.313139, 9.465458)
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(kassel, 10f))

        // Position the map
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(51.313139, 9.465458), 10f))

        // Initialize the manager with the context and the map
        // (Activity extends context, so we can pass 'this' in the constructor)
        clusterManager = ClusterManager(this, mMap)

        // Point the map's listeners at the listeners implemented by the cluster manager
        mMap.setOnCameraIdleListener(clusterManager)
        mMap.setOnMarkerClickListener(clusterManager)


        //use own renderer; allows customizing markers & clusters
        clusterManager.renderer = MyClusterRenderer(this, mMap, clusterManager)

        myClusterItemClickListener = MyClusterItemClickListener(this, mapFragment, mMap)
        myClusterClickListener = MyClusterClickListener(this, mMap)

        clusterManager.setOnClusterItemClickListener(myClusterItemClickListener)
        clusterManager.setOnClusterClickListener(myClusterClickListener)



        // Add cluster items (markers) to the cluster manager

        getCurrentData()

    }


    // Declare a variable for the cluster manager



    //used in function getCurrentData()
    private fun addItems(network: NetworkJson) {
        network.network.stations.forEach {

            val station = LatLng(it.latitude, it.longitude)
            //Snippet-String is sliced in class MyClusterRenderer in order to get free bikes and empty slots integer!
            val offsetItem = MyItem(it.timestamp, it.emptySlots.toString(), it.freeBikes.toString(), it.latitude, it.longitude, it.name, "Free bikes: " + it.freeBikes + "\nEmpty slots: " + it.emptySlots)

            clusterManager.addItem(offsetItem)
        }
    }

    // Get data from CityBikes API
    private fun getCurrentData() {

        var api = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(ApiRequests::class.java)

        GlobalScope.launch(Dispatchers.IO) {

            try {
                val response = api.getNextbikeData().awaitResponse()
                if (response.isSuccessful) {

                    var networks = response.body()!!

                    networks.networks.forEach {
                        if (it.location.country == "DE") {
                            GlobalScope.launch(Dispatchers.IO) {
                                api = Retrofit.Builder()
                                        .baseUrl(BASE_URL)
                                        .addConverterFactory(GsonConverterFactory.create())
                                        .build()
                                        .create(ApiRequests::class.java)

                                val response = api.getStations(it.id).awaitResponse()

                                if (response.isSuccessful) {

                                    var network = response.body()!!
                                    //loadMapMarkers(network)
                                    addItems(network)
                                }
                            }
                        }
                    }


                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    Toast.makeText(
                            applicationContext,
                            "Seems like something went wrong...",
                            Toast.LENGTH_SHORT
                    ).show()
                }
            }
        }
    }

    private fun loadMapMarkers(network: NetworkJson) {
        // @TODO Safe marker to update informations

        network.network.stations.forEach {

            val station = LatLng(it.latitude, it.longitude)
            this@MapsActivity.runOnUiThread(Runnable {
                mMap.addMarker(MarkerOptions()
                        .position(station)
                        .title(it.name)
                        .snippet("Free bikes: " + it.freeBikes)
                )
            })

        }
    }





}

One suggestion is to set a listener that would be called when all the cluster items/markers are loaded and then slightly change the map zoom level. In turn, all the cluster items will be shown on map.

zoom = googleMap.getCameraPosition().zoom;
latLng = googleMap.getCameraPosition().target;
newZoom = zoom + 0.0001f;
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,newZoom));

Works!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM