0Pricing
Android Academy · 课时

获取用户位置

了解融合位置提供程序基础

获取用户位置 是 CoddyKit 上的免费 Android Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 4 节课。

用户在哪里?

大多数基于位置的应用都会从一个问题开始:设备现在在哪里? Android 通过 Google Play 服务中的融合定位提供程序来回答这个问题。

在本课中,您将添加依赖项、请求一次位置、监听持续更新,并在 Compose 中显示结果。

为什么使用融合定位提供程序

Android 有多种位置来源:GPS、Wi-Fi 和基站。融合定位提供程序会智能地整合这些来源,在尽可能降低电量消耗的同时提供最佳位置。

现在几乎不再直接使用原始的 LocationManager——融合定位客户端更简单,也更智能。

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

声明权限

位置是一项敏感资源。请在您的 AndroidManifest.xml 中声明权限。使用 ACCESS_FINE_LOCATION 获取精确位置,或使用 ACCESS_COARSE_LOCATION 获取大致位置。

声明权限只是第一步——您还必须在运行时请求权限(后续课程会介绍)。

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

创建融合定位客户端

从 LocationServices 获取 FusedLocationProviderClient。在 Compose 中,使用 LocalContext.current 获取上下文,并记住该客户端,避免它在每次重组时重新创建。

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

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

获取最近的已知位置

最快的方式是使用 lastLocation——这是系统已经缓存的最近一次定位结果。它会返回一个 Task,因此请为其添加成功监听器。

如果近期没有应用请求过位置,它可能为 null,所以一定要进行空值检查。

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

使用协程等待任务完成

回调很快就会层层嵌套。kotlinx-coroutines-play-services 库提供了 .await(),让您可以使用简洁的挂起代码读取位置。

import kotlinx.coroutines.tasks.await

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

请求最新位置

lastLocation 可能已经过时。要获取最新定位结果,请调用带有优先级参数的 getCurrentLocation。PRIORITY_HIGH_ACCURACY 会使用 GPS;PRIORITY_BALANCED_POWER_ACCURACY 可以节省电量。

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()
}

持续获取位置更新

对于导航或跟踪,您需要持续接收位置更新。使用时间间隔构建 LocationRequest,然后通过 requestLocationUpdates 注册 LocationCallback。

完成后务必停止更新,以节省电量。

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 */ }
    }
}

将更新作为 Flow 获取

一种简洁的做法是将更新封装在 callbackFlow 中,这样消费者可以收集位置,而当收集结束时,更新会通过 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) }
}

在 Compose 中显示位置

在组合函数中收集结果:一次性读取时使用 LaunchedEffect,持续获取位置时使用 collectAsStateWithLifecycle。然后显示坐标。

@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..."
    )
}

电量与精度的权衡

位置获取是移动应用中最耗电的功能之一。请选择仍能满足需求的最低精度,使用可接受的最长更新间隔,并在界面离开后务必停止更新。

高精度加频繁更新会快速耗尽电量——请仅在主动导航时使用这种配置。

快速检查

您需要立即获取当前最精确的位置,并且要使用挂起函数。哪种方式最合适?

回顾

现在,您已经可以读取设备位置:

  • 添加 play-services-location,并声明 ACCESS_FINE/COARSE_LOCATION。
  • 从 LocationServices 获取 FusedLocationProviderClient。
  • 使用 lastLocation 获取缓存的位置,使用 getCurrentLocation 获取最新位置。
  • 通过 requestLocationUpdates / callbackFlow 持续获取更新,并在不需要时停止更新以节省电量。

接下来:绘制标记,并将相机移动到这些坐标。

常见问题解答

「获取用户位置」课时是免费的吗?

是的 — 「获取用户位置」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 4 节课。

「获取用户位置」这节课中我会学到什么?

了解融合位置提供程序基础 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Android Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「获取用户位置」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Android Academy 课中编写并运行代码吗?

能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 显示地图
  2. 获取用户位置
  3. 标记与摄像机
  4. 正确处理位置权限
← 返回 Android Academy