WearOS开发:Flutter调用Kotlin获取当前位置如何等待异步任务?
问题原因
你的Kotlin函数始终返回2.2,核心原因是fusedLocationClient.getCurrentLocation()是异步操作——它在后台线程执行定位逻辑,addOnSuccessListener中的赋值代码要等定位完成才会触发,但你的函数在调用完getCurrentLocation()后立刻返回了初始值,此时回调还未执行,自然拿不到真实位置。
解决方案
要等待异步任务完成后再返回结果,有两种常用实现方式:
方式一:用Kotlin协程(推荐)
借助kotlinx-coroutines-play-services库的扩展函数,让异步Task可以用await()等待完成,实现类似Flutter中await的效果。
- 添加依赖
在app模块的build.gradle中引入协程扩展库:
dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3" }
- 改写定位方法为挂起函数
// 借助Activity的lifecycleScope管理协程生命周期 private suspend fun getLocationLongitude(): Double { var longitude = 2.2 if (checkLocationPermission()) { val cancellationTokenSource = CancellationTokenSource() try { // 用await()等待定位任务完成 val location = fusedLocationClient.getCurrentLocation( android.location.LocationRequest.QUALITY_HIGH_ACCURACY, cancellationTokenSource.token ).await() longitude = location.longitude } catch (e: Exception) { // 处理定位失败、取消等异常 e.printStackTrace() } } return longitude } // 同理编写纬度获取方法 private suspend fun getLocationLatitude(): Double { var latitude = 2.2 if (checkLocationPermission()) { val cancellationTokenSource = CancellationTokenSource() try { val location = fusedLocationClient.getCurrentLocation( android.location.LocationRequest.QUALITY_HIGH_ACCURACY, cancellationTokenSource.token ).await() latitude = location.latitude } catch (e: Exception) { e.printStackTrace() } } return latitude }
- 在MethodChannel中用协程调用
// 初始化MethodChannel时设置处理器 MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "myapp/location_permission").setMethodCallHandler { call, result -> when (call.method) { // ...其他方法(requestPermission、checkPermission)的处理 "getLocationLongitude" -> { lifecycleScope.launch { val longitude = getLocationLongitude() result.success(longitude) } } "getLocationLatitude" -> { lifecycleScope.launch { val latitude = getLocationLatitude() result.success(latitude) } } } }
方式二:直接用Task回调传递结果
不使用协程,直接在getCurrentLocation()的成功/失败回调中,通过MethodChannel的Result对象返回结果,无需单独编写返回值函数。
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "myapp/location_permission").setMethodCallHandler { call, result -> when (call.method) { // ...其他方法处理 "getLocationLongitude" -> { if (!checkLocationPermission()) { result.success(2.2) return@setMethodCallHandler } val cancellationTokenSource = CancellationTokenSource() fusedLocationClient.getCurrentLocation( android.location.LocationRequest.QUALITY_HIGH_ACCURACY, cancellationTokenSource.token ).addOnSuccessListener { location -> result.success(location.longitude) }.addOnFailureListener { e -> // 定位失败返回默认值,也可通过result.error()返回错误信息 result.success(2.2) e.printStackTrace() } } "getLocationLatitude" -> { if (!checkLocationPermission()) { result.success(2.2) return@setMethodCallHandler } val cancellationTokenSource = CancellationTokenSource() fusedLocationClient.getCurrentLocation( android.location.LocationRequest.QUALITY_HIGH_ACCURACY, cancellationTokenSource.token ).addOnSuccessListener { location -> result.success(location.latitude) }.addOnFailureListener { e -> result.success(2.2) e.printStackTrace() } } } }
注意事项
- 两种方式都要处理无权限的情况,避免空指针或崩溃;
- 可以根据需求调整
LocationRequest的精度参数,比如用QUALITY_BALANCED_POWER_ACCURACY平衡功耗和精度; - 若定位超时,可以调用
cancellationTokenSource.cancel()取消任务。
内容的提问来源于stack exchange,提问作者Hoegje
相关产品推荐
相关产品推荐

