Android项目中获取当前位置时Task未完成异常的解决方法
问题分析与解决方案
核心问题
你直接调用fusedLocationProviderClient.lastLocation.result时触发异常,是因为lastLocation返回的是异步Task,位置获取操作还没完成就去取结果,必然会抛出Task is not yet complete。Thread.sleep()完全不可靠——不同设备获取位置的耗时差异极大,短了可能还是失败,长了会阻塞主线程导致ANR。
正确解决方案
针对Kotlin项目,推荐两种规范的处理方式:
方式一:用回调处理异步逻辑
修改函数,通过回调返回生成的坐标,避免阻塞主线程:
fun generateRandomCoordinates(min: Int, max: Int, onResult: (LatLng?) -> Unit) { val meterCord = 0.00900900900901 / 1000 val r = Random() // 修正随机范围:生成min到max之间的整数(包含两端) val randomMeters = r.nextInt(max - min + 1) + min val randomPM = r.nextInt(6) val metersCordN = meterCord * randomMeters.toDouble() fusedLocationProviderClient.lastLocation.addOnCompleteListener { task -> if (task.isSuccessful && task.result != null) { val currentLat = task.result.latitude val currentLong = task.result.longitude val coordinates = when (randomPM) { 0 -> LatLng(currentLat + metersCordN, currentLong + metersCordN) 1 -> LatLng(currentLat - metersCordN, currentLong - metersCordN) 2 -> LatLng(currentLat + metersCordN, currentLong - metersCordN) 3 -> LatLng(currentLat - metersCordN, currentLong + metersCordN) 4 -> LatLng(currentLat, currentLong - metersCordN) else -> LatLng(currentLat - metersCordN, currentLong) } onResult(coordinates) } else { // 位置获取失败,返回null自行处理 onResult(null) } } }
调用示例:
generateRandomCoordinates(0, 10000) { latLng -> latLng?.let { // 在这里添加地图标记 } ?: run { // 提示用户位置获取失败 } }
方式二:用Kotlin协程简化异步代码(推荐)
借助协程的await()方法,把异步逻辑写成同步风格的代码,避免回调嵌套:
- 先确保项目添加协程依赖(build.gradle):
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" implementation "com.google.android.gms:play-services-location:21.0.1"
- 修改为挂起函数:
import kotlinx.coroutines.tasks.await suspend fun generateRandomCoordinates(min: Int, max: Int): LatLng? { val meterCord = 0.00900900900901 / 1000 val r = Random() val randomMeters = r.nextInt(max - min + 1) + min val randomPM = r.nextInt(6) val metersCordN = meterCord * randomMeters.toDouble() return try { val location = fusedLocationProviderClient.lastLocation.await() location?.let { val currentLat = it.latitude val currentLong = it.longitude when (randomPM) { 0 -> LatLng(currentLat + metersCordN, currentLong + metersCordN) 1 -> LatLng(currentLat - metersCordN, currentLong - metersCordN) 2 -> LatLng(currentLat + metersCordN, currentLong - metersCordN) 3 -> LatLng(currentLat - metersCordN, currentLong + metersCordN) 4 -> LatLng(currentLat, currentLong - metersCordN) else -> LatLng(currentLat - metersCordN, currentLong) } } } catch (e: Exception) { // 捕获获取位置时的异常(比如权限不足) null } }
调用示例(在Activity/Fragment的协程作用域中):
lifecycleScope.launch { val randomLatLng = generateRandomCoordinates(0, 10000) randomLatLng?.let { // 添加地图标记 } ?: run { // 处理位置获取失败 } }
额外修正点
原代码还有个小bug:randomMeters = r.nextInt(max + min)生成的范围是0到max+min-1,不符合你要的10公里(0-10000米)范围,已经在上面的代码里修正为r.nextInt(max - min + 1) + min。
内容的提问来源于stack exchange,提问作者kndnba
相关产品推荐
相关产品推荐

