Skip to main content

Implementing Location Services

1. Requesting Location Permissions

Permission Description Required API Level Usage
ACCESS_FINE_LOCATION Allows access to precise location data including GPS and network-based location. API Level 1 Required for high-accuracy location services.
ACCESS_COARSE_LOCATION Allows access to approximate location sources such as network-based location. API Level 1 Used for less accurate but faster location data.

Example: Requesting Location Permissions in Android Manifest

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Note: Starting from Android 6.0 (API level 23), you must also request permissions at runtime.

2. Using FusedLocationProviderClient

Property Description Example
FusedLocationProviderClient Primary API for accessing location data in Android FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(this);
getLastLocation() Retrieves the most recent location client.getLastLocation().addOnSuccessListener { location -> ... }
requestLocationUpdates() Requests location updates at a specified interval client.requestLocationUpdates(locationRequest, locationCallback, null)

Example: Requesting Location Updates

val locationRequest = LocationRequest.create().apply {
    interval = 10000
    fastestInterval = 5000
    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}

val locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult) {
        locationResult.lastLocation?.let { location ->
            Log.d("Location", "Lat: ${location.latitude}, Lng: ${location.longitude}")
        }
    }
}

ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
    fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
}
Note: Ensure you have the ACCESS_FINE_LOCATION permission declared in your manifest and granted at runtime.
Warning: Location updates can drain battery quickly. Always stop updates when not needed.

3. Creating Location Requests

Property Description Values
priority Sets the priority of the location request Priority.PRIORITY_HIGH_ACCURACY, Priority.PRIORITY_BALANCED_POWER_ACCURACY, Priority.PRIORITY_LOW_POWER, Priority.PRIORITY_NO_POWER
interval How often the location should be updated (in milliseconds) 10000 (10 seconds)
fastestInterval Fastest interval at which the location can be updated (in milliseconds) 5000 (5 seconds)
smallestDisplacement Minimum distance between location updates (in meters) 10 (10 meters)

Example: Creating a Location Request

import android.location.Location
import com.google.android.gms.location.*

val locationRequest = LocationRequest.create()
    .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
    .setInterval(10000)
    .setFastestInterval(5000)
    .setSmallestDisplacement(10f)

4. Receiving Location Updates

Property Description Values
FusedLocationProviderClient Primary interface for accessing location services com.google.android.gms.location.FusedLocationProviderClient
LocationCallback Interface for receiving location updates com.google.android.gms.location.LocationCallback
LocationRequest Configuration for location updates com.google.android.gms.location.LocationRequest

Example: Requesting Location Updates

val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

val locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult) {
        for (location in locationResult.locations) {
            Log.d("Location", "Lat: ${location.latitude}, Lng: ${location.longitude}")
        }
    }
}

val locationRequest = LocationRequest.create().apply {
    interval = 10000
    fastestInterval = 5000
    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}

fusedLocationClient.requestLocationUpdates(
    locationRequest,
    locationCallback,
    Looper.getMainLooper()
)
Note: Ensure you have the necessary permissions in your manifest and runtime permissions granted before requesting location updates.
Property Description Values
priority Accuracy level for location updates PRIORITY_HIGH_ACCURACY, PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER, PRIORITY_NO_POWER
interval Interval between location updates (ms) Long
fastestInterval Fastest interval for location updates (ms) Long

Example: Setting Priority and Intervals

val locationRequest = LocationRequest.create().apply {
    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
    interval = 10000 // 10 seconds
    fastestInterval = 5000 // 5 seconds
}
Warning: High accuracy location updates can drain battery quickly. Consider using PRIORITY_LOW_POWER for background tasks.

Key Points

  • FusedLocationProviderClient is the main entry point for location services.
  • LocationCallback handles the actual location update events.
  • LocationRequest configures how often and how accurately to receive updates.
  • Always request runtime permissions for ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION.

5. Removing Location Updates

Method Description Notes
removeLocationUpdates() Removes location updates from a LocationListener Must be called with the same listener instance used to register updates
removeLocationUpdates() Removes location updates from a PendingIntent Must be called with the same PendingIntent instance used to register updates

Example: Removing Location Updates with Listener

val locationListener = object : LocationListener {
    override fun onLocationChanged(location: Location) {
        // Handle location update
    }
}

// Remove updates
locationManager.removeLocationUpdates(locationListener)

Example: Removing Location Updates with PendingIntent

val intent = Intent(context, LocationReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)

// Remove updates
locationManager.removeLocationUpdates(pendingIntent)

6. Using Geocoding

Property Description Example
Geocoder Class for converting addresses to coordinates and vice versa Geocoder geocoder = Geocoder.getInstance(context);
getFromLocation Converts latitude and longitude to a list of addresses List<Address> addresses = geocoder.getFromLocation(40.7128, -74.0060, 1);
getFromLocationName Converts address string to a list of coordinates List<Address> addresses = geocoder.getFromLocationName("New York City", 1);

Example: Reverse Geocoding

val geocoder = Geocoder(context)
val addresses = geocoder.getFromLocation(40.7128, -74.0060, 1)
val address = addresses[0]
val fullAddress = address.getAddressLine(0)

Example: Forward Geocoding

val geocoder = Geocoder(context)
val addresses = geocoder.getFromLocationName("New York City", 1)
val latLng = LatLng(addresses[0].latitude, addresses[0].longitude)
Note: Geocoding requires internet permission and may have rate limits. Always handle exceptions for network or invalid address errors.

7. Calculating Distance Between Locations

Method Description Parameters Return Type
distanceBetween Calculates the distance between two geographical points latitude1: Double, longitude1: Double, latitude2: Double, longitude2: Double Float

Example: Calculating Distance

import android.location.Location

val location1 = Location("provider")
location1.latitude = 40.7128
location1.longitude = -74.0060

val location2 = Location("provider")
location2.latitude = 34.0522
location2.longitude = -118.2437

val distanceInMeters = location1.distanceTo(location2)
println("Distance: $distanceInMeters meters")
Note: The distanceTo method returns the distance in meters.

8. Checking Location Settings

Setting Description Status
Location Mode Indicates whether location is enabled and the accuracy level (High, Medium, Low) NEW
GPS Enabled Whether GPS is turned on DEPRECATED
Network Location Whether network-based location is enabled NEW

Example: Check Location Settings

import android.content.Context
import android.location.LocationManager
import android.provider.Settings

fun isLocationEnabled(context: Context): Boolean {
    val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
           locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
}

fun getLocationMode(context: Context): String {
    val mode = Settings.Secure.getString(
        context.contentResolver,
        Settings.Secure.LOCATION_MODE
    )
    return mode ?: "0"
}
Note: On Android 6.0+, you must request ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions at runtime.
Warning: LOCATION_MODE is not available in all Android versions and may return null or default values.

9. Implementing Geofencing

Geofencing allows you to define virtual perimeters around real-world locations and receive notifications when a device enters or exits these areas.

Property Description Values
Geofence Represents a circular area defined by latitude, longitude, and radius Geofence.Builder().setCircularRegion(latitude, longitude, radius)
GeofencingClient Interface to manage geofences and handle geofence transition events GeofencingClient client = LocationServices.getGeofencingClient(context)
GeofenceStatus Represents the status of a geofence (ENTER, EXIT, Dwell) Geofence.GEOFENCE_ENTER, Geofence.GEOFENCE_EXIT, Geofence.GEOFENCE_DWELL

Example: Creating a Geofence

val geofence = Geofence.Builder()
    .setRequestId("geofence-1")
    .setCircularRegion(37.7749, -122.4194, 100f)
    .setExpirationDuration(Geofence.NEVER_EXPIRES)
    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
    .build()

Example: Adding Geofences

val geofenceList = listOf(geofence)
val geofencingRequest = GeofencingRequest.Builder()
    .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
    .addGeofences(geofenceList)
    .build()

val geofencingClient = LocationServices.getGeofencingClient(context)
geofencingClient.addGeofences(geofencingRequest, geofencePendingIntent)

Example: Handling Geofence Transitions

class GeofenceBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val geofencingEvent = GeofencingEvent.fromIntent(intent)
        if (geofencingEvent.hasError()) {
            val errorCode = geofencingEvent.errorCode
            Log.e("Geofence", "Error code: $errorCode")
            return
        }

        val transition = geofencingEvent.geofenceTransition
        val geofenceIds = geofencingEvent.triggeringGeofences.map { it.requestId }

        when (transition) {
            Geofence.GEOFENCE_TRANSITION_ENTER -> {
                Log.d("Geofence", "Entered: $geofenceIds")
            }
            Geofence.GEOFENCE_TRANSITION_EXIT -> {
                Log.d("Geofence", "Exited: $geofenceIds")
            }
        }
    }
}
Note: Ensure that the app has location permissions and background access to receive geofence transitions when the app is not in the foreground.

10. Handling Background Location

Permission Description Android Version
ACCESS_BACKGROUND_LOCATION Allows app to access location in background Android 10 (API 29)

Example: Request Background Location Permission

val permission = Manifest.permission.ACCESS_BACKGROUND_LOCATION
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, arrayOf(permission), REQUEST_CODE)
}
Note: Background location access requires explicit user permission and is subject to strict battery optimization rules.
API Description Status
FusedLocationProviderClient Provides location updates including background NEW
LocationCallback Receives location updates Stable

Example: Background Location Update

val locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult) {
        locationResult.lastLocation?.let { location ->
            // Handle background location update
            Log.d("Location", "Background: ${location.latitude}, ${location.longitude}")
        }
    }
}

val locationRequest = LocationRequest.Builder(10000).apply {
    setPriority(Priority.PRIORITY_BALANCED_POWER_ACCURACY)
    setInterval(10000)
    setFastestInterval(5000)
}.build()

fusedLocationClient.requestLocationUpdates(
    locationRequest,
    locationCallback,
    Looper.getMainLooper()
)

Was this article helpful?