0Pricing
Android Academy · Lesson

Getting the User Location

Fused location provider basics.

Getting the User Location is a free Android Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Where Is the User?

Most location-aware apps start with one question: where is the device right now? Android answers this through the Fused Location Provider, part of Google Play services.

In this lesson you'll add the dependency, request a single location, listen for continuous updates, and surface the result in Compose.

Why the Fused Provider

Android has several location sources: GPS, Wi-Fi, and cell towers. The Fused Location Provider intelligently blends them to give you the best location with the least battery drain.

You almost never use raw LocationManager directly anymore — the fused client is simpler and smarter.

// build.gradle.kts (module)
dependencies {
    implementation("com.google.android.gms:play-services-location:21.3.0")
}

Declaring the Permission

Location is a sensitive resource. Declare the permission in your AndroidManifest.xml. Use ACCESS_FINE_LOCATION for precise positioning or ACCESS_COARSE_LOCATION for approximate.

Declaring it is only step one — you must also request it at runtime (covered in a later lesson).

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Creating the Fused Client

Get a FusedLocationProviderClient from LocationServices. In Compose, grab the context with LocalContext.current and remember the client so it isn't recreated each recomposition.

import com.google.android.gms.location.LocationServices

@Composable
fun rememberFusedClient() = run {
    val context = LocalContext.current
    remember {
        LocationServices.getFusedLocationProviderClient(context)
    }
}

Getting the Last Known Location

The fastest answer is lastLocation — the most recent fix the system already cached. It returns a Task, so attach a success listener.

It can be null if no app has requested a location recently, so always null-check.

@SuppressLint("MissingPermission")
fun fetchLastLocation(
    client: FusedLocationProviderClient,
    onResult: (Location?) -> Unit
) {
    client.lastLocation
        .addOnSuccessListener { location -> onResult(location) }
        .addOnFailureListener { onResult(null) }
}

Awaiting the Task with Coroutines

Callbacks nest quickly. The kotlinx-coroutines-play-services library adds .await() so you can read a location with clean suspending code.

import kotlinx.coroutines.tasks.await

@SuppressLint("MissingPermission")
suspend fun currentLastLocation(
    client: FusedLocationProviderClient
): Location? {
    return client.lastLocation.await()
}

Requesting a Fresh Location

lastLocation may be stale. For an up-to-date fix, call getCurrentLocation with a priority. PRIORITY_HIGH_ACCURACY uses GPS; PRIORITY_BALANCED_POWER_ACCURACY saves battery.

import com.google.android.gms.location.Priority
import com.google.android.gms.location.CurrentLocationRequest

@SuppressLint("MissingPermission")
suspend fun freshLocation(
    client: FusedLocationProviderClient
): Location? {
    val request = CurrentLocationRequest.Builder()
        .setPriority(Priority.PRIORITY_HIGH_ACCURACY)
        .build()
    return client.getCurrentLocation(request, null).await()
}

Continuous Location Updates

For navigation or tracking you need a stream of updates. Build a LocationRequest with an interval, then register a LocationCallback via requestLocationUpdates.

Always stop updates when you're done to save battery.

import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationCallback

val request = LocationRequest.Builder(
    Priority.PRIORITY_HIGH_ACCURACY,
    5000L // 5 seconds
).build()

val callback = object : LocationCallback() {
    override fun onLocationResult(result: LocationResult) {
        result.lastLocation?.let { /* use it */ }
    }
}

Updates as a Flow

A clean pattern wraps updates in a callbackFlow, so consumers collect locations and updates stop automatically when collection ends via awaitClose.

import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow

@SuppressLint("MissingPermission")
fun FusedLocationProviderClient.locationFlow(request: LocationRequest) = callbackFlow {
    val cb = object : LocationCallback() {
        override fun onLocationResult(result: LocationResult) {
            result.lastLocation?.let { trySend(it) }
        }
    }
    requestLocationUpdates(request, cb, Looper.getMainLooper())
    awaitClose { removeLocationUpdates(cb) }
}

Showing Location in Compose

Collect the result in a composable using LaunchedEffect for a one-shot read, or collectAsStateWithLifecycle for a stream. Then display the coordinates.

@Composable
fun LocationLabel(client: FusedLocationProviderClient) {
    var location by remember { mutableStateOf<Location?>(null) }
    LaunchedEffect(Unit) {
        location = freshLocation(client)
    }
    Text(
        location?.let { "Lat ${it.latitude}, Lng ${it.longitude}" }
            ?: "Locating..."
    )
}

Battery and Accuracy Trade-offs

Location is one of the biggest battery costs in mobile apps. Choose the lowest accuracy that still meets your needs, use the longest acceptable update interval, and always stop updates when the screen is gone.

High accuracy + frequent updates drains batteries fast — reserve it for active navigation.

Quick Check

You need the single most accurate current position right now, using a suspending function. Which approach fits best?

Recap

You can now read the device location:

  • Add play-services-location and declare ACCESS_FINE/COARSE_LOCATION.
  • Get a FusedLocationProviderClient from LocationServices.
  • Use lastLocation for a cached fix, getCurrentLocation for a fresh one.
  • Stream updates via requestLocationUpdates / a callbackFlow, and stop them to save battery.

Next: drawing markers and moving the camera to those coordinates.

Frequently asked questions

Is the “Getting the User Location” lesson free?

Yes — the full text of “Getting the User Location” is free to read here on the web, and the Android Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Android Academy course, upgrade to CoddyKit PRO.

What will I learn in “Getting the User Location”?

Fused location provider basics. You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Android Academy?

No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Getting the User Location” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Android Academy lesson?

Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Showing a Map
  2. Getting the User Location
  3. Markers and Camera
  4. Location Permissions Done Right
← Back to Android Academy