Move marker instead of adding it after requestLocationUpdates in kotlin

2.5k views Asked by At

I'm using google map in kotlin with help of this tutorial Introduction to Google Maps API for Android with Kotlin. in this tutorial showed how can add a marker after location updated but when it updated,there is still a marker in previous location and added again and again. there is no object of Marker in this code and i want remain first added marker and then move it. how can i do this? Thanks

 class MapsActivity : AppCompatActivity(), OnMapReadyCallback,
    GoogleMap.OnMarkerClickListener {

private lateinit var map: GoogleMap
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var lastLocation: Location

private lateinit var locationCallback: LocationCallback
private lateinit var locationRequest: LocationRequest
private var locationUpdateState = false

companion object {
    private const val LOCATION_PERMISSION_REQUEST_CODE = 1
    private const val REQUEST_CHECK_SETTINGS = 2
    private const val PLACE_PICKER_REQUEST = 3
}

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.
    val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
    mapFragment.getMapAsync(this)

    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

    locationCallback = object : LocationCallback() {
        override fun onLocationResult(p0: LocationResult) {
            super.onLocationResult(p0)

            lastLocation = p0.lastLocation
            placeMarkerOnMap(LatLng(lastLocation.latitude, lastLocation.longitude))
        }
    }

    createLocationRequest()

    val fab = findViewById<FloatingActionButton>(R.id.fab)
    fab.setOnClickListener {
        loadPlacePicker()
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_CHECK_SETTINGS) {
        if (resultCode == Activity.RESULT_OK) {
            locationUpdateState = true
            startLocationUpdates()
        }
    }
    if (requestCode == PLACE_PICKER_REQUEST) {
        if (resultCode == RESULT_OK) {
            val place = PlacePicker.getPlace(this, data)
            var addressText = place.name.toString()
            addressText += "\n" + place.address.toString()

            placeMarkerOnMap(place.latLng)
        }
    }
}

override fun onPause() {
    super.onPause()
    fusedLocationClient.removeLocationUpdates(locationCallback)
}

public override fun onResume() {
    super.onResume()
    if (!locationUpdateState) {
        startLocationUpdates()
    }
}

override fun onMapReady(googleMap: GoogleMap) {
    map = googleMap

    map.uiSettings.isZoomControlsEnabled = true
    map.setOnMarkerClickListener(this)

    setUpMap()
}

override fun onMarkerClick(p0: Marker?) = true

private fun setUpMap() {
    if (ActivityCompat.checkSelfPermission(this,
            android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
        return
    }

    map.isMyLocationEnabled = true
    map.mapType = GoogleMap.MAP_TYPE_NORMAL

    fusedLocationClient.lastLocation.addOnSuccessListener(this) { location ->
        // Got last known location. In some rare situations this can be null.
        if (location != null) {
            lastLocation = location
            val currentLatLng = LatLng(location.latitude, location.longitude)
            placeMarkerOnMap(currentLatLng)
            map.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 12f))
        }
    }
}

private fun placeMarkerOnMap(location: LatLng) {
    val markerOptions = MarkerOptions().position(location)

    val titleStr = getAddress(location)  // add these two lines
    markerOptions.title(titleStr)

    map.addMarker(markerOptions)

}


private fun startLocationUpdates() {
    if (ActivityCompat.checkSelfPermission(this,
            android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
                LOCATION_PERMISSION_REQUEST_CODE)
        return
    }
    fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null /* Looper */)

}

private fun createLocationRequest() {
    locationRequest = LocationRequest()
    locationRequest.interval = 10000
    locationRequest.fastestInterval = 5000
    locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY

    val builder = LocationSettingsRequest.Builder()
            .addLocationRequest(locationRequest)
    val client = LocationServices.getSettingsClient(this)
    val task = client.checkLocationSettings(builder.build())

    task.addOnSuccessListener {
        locationUpdateState = true
        startLocationUpdates()
    }
    task.addOnFailureListener { e ->
        if (e is ResolvableApiException) {
            // Location settings are not satisfied, but this can be fixed
            // by showing the user a dialog.
            try {
                // Show the dialog by calling startResolutionForResult(),
                // and check the result in onActivityResult().
                e.startResolutionForResult(this@MapsActivity,
                        REQUEST_CHECK_SETTINGS)
            } catch (sendEx: IntentSender.SendIntentException) {
                // Ignore the error.
            }
        }
    }
}

private fun loadPlacePicker() {
    val builder = PlacePicker.IntentBuilder()

    try {
        startActivityForResult(builder.build(this@MapsActivity), PLACE_PICKER_REQUEST)
    } catch (e: GooglePlayServicesRepairableException) {
        e.printStackTrace()
    } catch (e: GooglePlayServicesNotAvailableException) {
        e.printStackTrace()
    }
}
}
2

There are 2 answers

0
LordRaydenMK On

The addMarker() method of GoogleMap returns a Marker.

You need to keep a reference to the returned marker and later update it's position using the setPosition method.

0
tommybomb On

@LordRaydenMK's answer is correct. I spent a week trying to work this out and found finally got it. That raywenderlich tutorial you referenced is good, except they incorrectly coded the placeMarkerOnMap() function.

First, set a variable for your location marker above onCreate:

private var userLocationMarker: Marker? = null

Then replace your placeMarkerOnMap() function with this code and it should work fine:

private fun placeMarkerOnMap(location: Location) {
    val latLng = LatLng(location.latitude, location.longitude)
    if (userLocationMarker == null) {
        //Create a new marker
        val markerOptions = MarkerOptions()
        markerOptions.position(latLng)
        markerOptions.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_user_location))
        markerOptions.rotation(location.bearing)
        markerOptions.anchor(0.5.toFloat(), 0.5.toFloat())
        userLocationMarker = map.addMarker(markerOptions)
        map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 20f))
    } else {
        //use the previously created marker
        userLocationMarker!!.position = latLng
        userLocationMarker!!.rotation = location.bearing
        map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 20f))
    }
}

If you want to get rid of the blue dot make sure to set isMyLocationEnabled to false.