milosev.com
  • Home
    • List all categories
    • Sitemap
  • Downloads
    • WebSphere
    • Hitachi902
    • Hospital
    • Kryptonite
    • OCR
    • APK
  • About me
    • Gallery
      • Italy2022
      • Côte d'Azur 2024
    • Curriculum vitae
      • Resume
      • Lebenslauf
    • Social networks
      • Facebook
      • Twitter
      • LinkedIn
      • Xing
      • GitHub
      • Google Maps
      • Sports tracker
    • Adventures planning
  1. You are here:  
  2. Home
  3. Android

Get the last known location with LocationManager

Details
Written by: Stanko Milosev
Category: Android
Published: 30 November 2025
Last Updated: 09 December 2025
Hits: 19
  • kotlin
Hier I gave one example of getting the last known location with FusedLocationProviderClient

Now here is example with LocationManager:

Example with trailing lambdas:

val locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(
	LocationManager.GPS_PROVIDER,
	1000L,
	0f
) { location ->
	logger.log("\nLat: " + location.latitude.toString()
			+ "\nLon: " + location.longitude.toString()
			+ "\nAltitude" + location.altitude.toString())
}
but in order to be able to stop requests, declare lamba like function:
private lateinit var gpsListener: LocationListener
...
gpsListener = LocationListener { location ->
	logger.log(
				"\nLat: " + location.latitude.toString()
				+ "\nLon: " + location.longitude.toString()
				+ "\nAltitude" + location.altitude.toString()
	)
}

locationManager.requestLocationUpdates(
	LocationManager.GPS_PROVIDER,
	1000L,
	0f,
	gpsListener
)
Stop it like this:
locationManager.removeUpdates(gpsListener)
Example download from here.

Get the last known location with FusedLocationProviderClient

Details
Written by: Stanko Milosev
Category: Android
Published: 29 November 2025
Last Updated: 30 November 2025
Hits: 45
  • kotlin
In "\app\build.gradle.kts"I have added:
implementation("com.google.android.gms:play-services-location:21.3.0")
in "\app\src\main\AndroidManifest.xml"
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Shortly, I am using this code to receive last known location
var locationRequest: LocationRequest
val localInterval: Long = 0
locationRequest = LocationRequest.Builder(
	Priority.PRIORITY_HIGH_ACCURACY, TimeUnit.SECONDS.toMillis(localInterval)
).apply {
	setGranularity(Granularity.GRANULARITY_PERMISSION_LEVEL)
	setDurationMillis(TimeUnit.MINUTES.toMillis(Long.MAX_VALUE))
	setWaitForAccurateLocation(true)
	setMaxUpdates(Int.MAX_VALUE)
	setIntervalMillis(TimeUnit.SECONDS.toMillis(localInterval))
	setMinUpdateIntervalMillis(TimeUnit.SECONDS.toMillis(localInterval))
	setMinUpdateDistanceMeters(0F)
}.build()
val locationCallback = object : LocationCallback() {
	override fun onLocationResult(locationResultLocal: LocationResult) {
		logger.log("\nLat: " + locationResultLocal.lastLocation?.latitude.toString()
				+ "\nLon: " + locationResultLocal.lastLocation?.longitude.toString()
				+ "\nAltitude" + locationResultLocal.lastLocation?.altitude.toString())
	}
}

val fusedLocationClient = LocationServices.getFusedLocationProviderClient(myActivity)
fusedLocationClient.requestLocationUpdates(
	locationRequest, locationCallback, Looper.getMainLooper()
)
Notice line:
setMinUpdateIntervalMillis(TimeUnit.SECONDS.toMillis(localInterval))
With setMinUpdateIntervalMillis I am reciving location as soon as possible, constantly, without stopping.

To stop location updates use this code:

fusedLocationClient.removeLocationUpdates(locationCallback)
My class for starting / stoping location updates looks like this:
package com.example.testsandbox

import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.os.Looper
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.Granularity
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import java.util.concurrent.TimeUnit

class MyFusedLocationClient(var logger: ILogger) {
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    lateinit var myActivity: Activity

    var locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResultLocal: LocationResult) {
            logger.log("\nLat: " + locationResultLocal.lastLocation?.latitude.toString()
                    + "\nLon: " + locationResultLocal.lastLocation?.longitude.toString()
                    + "\nAltitude" + locationResultLocal.lastLocation?.altitude.toString())
        }
    }

    fun startLocationUpdates() {
        myRequestLocationUpdates(myActivity)
    }

    fun stopLocationUpdates() {
        fusedLocationClient.removeLocationUpdates(locationCallback)
    }

    private fun myRequestLocationUpdates(myActivity: Activity) {

        if (ActivityCompat.checkSelfPermission(
                myActivity,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                myActivity,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                myActivity,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION
            )
        }

        var locationRequest: LocationRequest
        val localInterval: Long = 0
        locationRequest = LocationRequest.Builder(
            Priority.PRIORITY_HIGH_ACCURACY, TimeUnit.SECONDS.toMillis(localInterval)
        ).apply {
            setGranularity(Granularity.GRANULARITY_PERMISSION_LEVEL)
            setDurationMillis(TimeUnit.MINUTES.toMillis(Long.MAX_VALUE))
            setWaitForAccurateLocation(true)
            setMaxUpdates(Int.MAX_VALUE)
            setIntervalMillis(TimeUnit.SECONDS.toMillis(localInterval))
            setMinUpdateIntervalMillis(TimeUnit.SECONDS.toMillis(localInterval))
            setMinUpdateDistanceMeters(0F)
        }.build()

        fusedLocationClient = LocationServices.getFusedLocationProviderClient(myActivity)
        fusedLocationClient.requestLocationUpdates(
            locationRequest, locationCallback, Looper.getMainLooper()
        )
    }

    companion object {
        const val REQUEST_LOCATION_PERMISSION = 123
    }

}
In activty use it like this:
val myFusedLocationClient = MyFusedLocationClient(logger)
myFusedLocationClient.myActivity = this
...
myFusedLocationClient.startLocationUpdates()
...
myFusedLocationClient.stopLocationUpdates()
Full example downlaod from here.

Reloading a KML Layer in Google Maps in a Loop

Details
Written by: Stanko Milosev
Category: Android
Published: 16 November 2025
Last Updated: 19 November 2025
Hits: 60
  • kotlin
Here I gave the simplest possible example of loading a KML in Google Maps, using HttpURLConnection.

In this example I will use retrofit. Here I gave simplest possible GET and POST example in Kotlin, but problem with that solution is that I am using enqueue and Call return type which means that my every request will be send to sort of a queue, until is finished, and if I want to execute it in a loop, I can end in OutOfMemory very easy, which is why I decided rather to use coroutines and Response return type. Read more about Response here

The problem I was trying to solve was how to load a KML file in real time—in a loop—without running into an OutOfMemory exception. One solution I already wrote here, now here is a complete one.

My API endpoint looks like this:

interface IGetKml {
    @GET
    suspend fun getKml(@Url url: String): Response<ResponseBody>
}
Notice that getKml is suspending function.

The class that actually loads the KML looks like this:

package com.milosev.googlemapstestsandbox

import android.content.Context
import android.util.Log
import com.google.android.gms.maps.GoogleMap
import com.google.maps.android.data.kml.KmlLayer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
import java.io.ByteArrayInputStream
import java.net.URL

class LoadKml {

    private var kmlLayer: KmlLayer? = null

    suspend fun execute(activity: Context, googleMap: GoogleMap, strUrl: String) {

        val url = URL(strUrl)
        val kmlClient = CreateRetrofitBuilder().createRetrofitBuilder("${url.protocol}://${url.host}/")
            .create(IGetKml::class.java)

        withContext(Dispatchers.IO) {
            while (isActive)
            {
                try {
                    val webApiRequest =
                        kmlClient.getKml(strUrl);

                    if (webApiRequest.isSuccessful) {
                        val bytes = webApiRequest.body()?.bytes()
                        if (bytes != null) {

                            val input = ByteArrayInputStream(bytes)

                            withContext(Dispatchers.Main) {
                                kmlLayer?.removeLayerFromMap()
                                Log.i("KML", "Removed successfully")

                                kmlLayer = KmlLayer(googleMap, input, activity)
                                kmlLayer?.addLayerToMap()
                                Log.i("KML", "Loaded successfully")
                            }
                        }
                    } else {
                        Log.e("KML", "Error: ${webApiRequest.code()}")
                    }

                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
    }
}
Notice that execute is also suspend function and also notice that I am starting loop with Dispatchers.IO, but KML I will add in Dispatchers.Main

Here is MainActivity.kt

package com.milosev.googlemapstestsandbox

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
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.milosev.googlemapstestsandbox.databinding.ActivityMainBinding
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity(), OnMapReadyCallback {

    private var kmlUpdateJob: Job? = null
    private lateinit var binding: ActivityMainBinding
    private lateinit var map: GoogleMap

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

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)

        val mainActivity = this
        var isStarted = false

        binding.btnLoadKml.setOnClickListener {
            isStarted = !isStarted

            if (isStarted) {
                binding.btnLoadKml.text = "Stop"
                val loadKml = LoadKml()
                kmlUpdateJob = lifecycleScope.launch {
                    loadKml.execute(mainActivity, map, binding.etKmlUrl.text.toString())
                }
            }
            else {
                kmlUpdateJob?.cancel()
                kmlUpdateJob = null
                binding.btnLoadKml.text = "Start"
            }
        }
    }

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

        val tunis = LatLng(35.7607919, 10.7537573)
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(tunis, 8f))
    }
}
Notice how I am starting to load KML using job:
private var kmlUpdateJob: Job? = null
...
kmlUpdateJob = lifecycleScope.launch {
	loadKml.execute(mainActivity, map, binding.etKmlUrl.text.toString())
}
...
kmlUpdateJob?.cancel()
kmlUpdateJob = null
Example download from here.

Remove KmlLayer from the Map to avoid OutOfMemory

Details
Written by: Stanko Milosev
Category: Android
Published: 12 November 2025
Last Updated: 12 November 2025
Hits: 56
  • kotlin
Example:
private var kmlLayer: KmlLayer? = null
...
kmlLayer?.removeLayerFromMap()
kmlLayer = KmlLayer(googleMap, input, activity)
kmlLayer?.addLayerToMap()
  1. Load KML in Google Maps
  2. Simple Google Maps example
  3. Receiver as separate class
  4. Foreground service as a separate process example

Page 1 of 13

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10