Skip to content

Android Location Provider — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about Android Location Provider. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

The Problem

Your location updates are inaccurate (off by 500m), or you get null location from the Fused Location Provider.

Wrong Approach ❌

// Using coarse location only
val locationRequest = LocationRequest.create().apply {
    priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY // ~100m accuracy
}
// Getting last known location without checking recency
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
    // location may be hours old!
}

Output: Low accuracy. Stale location returned.

Right Approach ✅

class LocationManager(private val context: Context) {
    private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)

    // High accuracy location request
    fun getHighAccuracyLocation(): Task<Location> {
        val locationRequest = LocationRequest.create().apply {
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY // GPS required
            interval = 10000 // 10 seconds
            fastestInterval = 5000
            smallestDisplacement = 10f // 10 meters
        }

        return fusedLocationClient.requestLocationUpdates(
            locationRequest,
            createLocationCallback(),
            Looper.getMainLooper()
        ).continueWith { task ->
            // Return current location after first update
            fusedLocationClient.lastLocation.result
        }
    }

    // Get last known location with recency check
    suspend fun getFreshLocation(): Location? {
        val location = fusedLocationClient.lastLocation.await()

        // Check if location is recent enough
        if (location != null) {
            val age = System.currentTimeMillis() - location.time
            if (age < 5 * 60 * 1000) { // Less than 5 minutes old
                return location
            }
        }

        // Request a fresh location update
        return requestSingleUpdate()
    }

    private suspend fun requestSingleUpdate(): Location? {
        val locationRequest = LocationRequest.create().apply {
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
            numUpdates = 1 // Single update
            interval = 0
            fastestInterval = 0
        }

        return suspendCancellableCoroutine { cont ->
            val callback = object : LocationCallback() {
                override fun onLocationResult(result: LocationResult) {
                    cont.resume(result.lastLocation)
                }

                override fun onLocationAvailability(availability: LocationAvailability) {
                    if (!availability.isLocationAvailable) {
                        cont.resume(null)
                    }
                }
            }

            fusedLocationClient.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper())
                .addOnFailureListener { cont.resume(null) }

            cont.invokeOnCancellation {
                fusedLocationClient.removeLocationUpdates(callback)
            }
        }
    }

    // Geocoding (reverse geocode)
    suspend fun getAddress(lat: Double, lng: Double): String? {
        val geocoder = Geocoder(context, Locale.getDefault())
        return geocoder.getFromLocation(lat, lng, 1)?.firstOrNull()?.getAddressLine(0)
    }
}

Output: Accurate location with recency checks.

Prevention

  • Use PRIORITY_HIGH_ACCURACY when GPS accuracy is needed.
  • Check location timestamp for recency before trusting lastLocation.
  • Use numUpdates = 1 for a single fresh location request.
  • Request location permission before using FusedLocationProvider.
  • Fall back to PRIORITY_BALANCED_POWER_ACCURACY when GPS is disabled.

Common Mistakes with location provider

  1. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  2. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  3. Using return to exit a function early instead of wrapping a pure value in the monad

These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What is the difference between PRIORITY_HIGH_ACCURACY and PRIORITY_BALANCED_POWER_ACCURACY?

HIGH_ACCURACY uses GPS (~5m accuracy, more battery). BALANCED uses WiFi/cell (~100m accuracy, less battery). Choose based on your accuracy requirements.

### Why does lastLocation return null?

Last location may be null if no provider has ever determined location, or if location is disabled. After a successful requestLocationUpdates(), lastLocation will have a value.

### How do I check if GPS is enabled?

Use locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER). If not enabled, prompt the user with Settings.ACTION_LOCATION_SOURCE_SETTINGS intent.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro