使用FusedLocationProvider请求位置时遇Task未完成异常,求解决方案
问题分析与解决方案
为什么会触发这个异常?
fusedLocationClient.lastLocation是一个异步Task,它不会立即返回设备位置,而是在后台完成位置查询后,通过addOnSuccessListener回调返回结果。你在调用addOnSuccessListener后立刻尝试获取callbacklocation.result,此时Task还处于未完成状态,直接访问result就会抛出IllegalStateException。
正确实现步骤
结合Jetpack Compose的状态管理,我们需要用可观察状态保存位置,当异步任务完成后更新状态,Compose会自动重组UI展示地图。同时还要处理权限、位置为空的边界情况:
1. 修正后的完整代码
class MainActivity : AppCompatActivity() { @SuppressLint("MissingPermission") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) setContent { MapsTestTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { // 用Compose状态保存位置,初始为null val userLocation = remember { mutableStateOf<LatLng?>(null) } // 启动异步位置请求,仅在Composable首次加载时执行 LaunchedEffect(Unit) { fusedLocationClient.lastLocation .addOnSuccessListener { location: Location? -> location?.let { userLocation.value = LatLng(it.latitude, it.longitude) } } .addOnFailureListener { // 处理位置请求失败的情况,比如权限不足或无缓存位置 Log.e("LocationError", "获取位置失败: ${it.message}") } } // 根据位置状态展示对应UI userLocation.value?.let { location -> ShowLastLocation(location) } ?: run { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text(text = "正在获取位置...") } } } } } } @Composable fun ShowLastLocation(location: LatLng) { GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(location, 10f) } ) { Marker( state = MarkerState(position = location), title = "你的位置" ) } } }
2. 关键改进点
- Compose状态管理:用
mutableStateOf保存位置,位置更新时Compose自动触发UI重组。 - 异步操作规范:用
LaunchedEffect包裹位置请求,确保仅在Composable首次加载时执行一次,避免重复请求。 - 回调正确处理:在
addOnSuccessListener中更新状态,而非直接访问未完成的Task结果。 - 边界情况处理:增加位置为空时的加载提示,以及失败回调捕获错误。
- 权限提示:实际开发中要移除
@SuppressLint("MissingPermission"),先通过ActivityResultContracts.RequestPermission完成运行时权限申请,再发起位置请求。
内容的提问来源于stack exchange,提问作者Asmath
相关产品推荐
相关产品推荐

