获取用户位置
了解融合位置提供程序基础
获取用户位置 是 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 反馈 — 无需本地设置。