如何在Kotlin协程外部获取协程内部生成的变量值
问题根源
你碰到的不是变量跨作用域传值的问题,是异步代码执行顺序不对:
- Firestore的
get()是异步网络请求,addOnCompleteListener回调、你自己开的IO协程里的逻辑,都不会阻塞外层onMapReady的执行 - 你写在协程外面的
addMarker、moveCamera会在网络请求还没返回、loc变量还没生成的时候就直接执行,就算你在外层声明个可变变量等协程里赋值,这两行操作地图的代码拿到的也只会是初始的硬编码值,根本等不到异步结果。
最简实现方案
不用搞复杂的接口回调、LiveData之类的东西,直接把依赖坐标的地图操作挪到协程里拿到结果之后执行就行,注意操作UI必须切主线程,优化后的代码如下:
override fun onMapReady(googleMap: GoogleMap) { mMap = googleMap val routenuebergabe = intent.getStringExtra("tourname").toString() // 用页面生命周期绑定的lifecycleScope开协程,页面销毁自动取消任务,避免内存泄漏 lifecycleScope.launch { // 先给个默认兜底坐标 var startlocation = LatLng(49.7913, 9.9534) try { // Firestore KTX库自带await()挂起函数,不需要额外套addOnCompleteListener回调 val doc = Firebase.firestore.collection("Routen") .document(routenuebergabe) .get() .await() val koors = doc.get("starting_location").toString() val strs = koors.split(",").toTypedArray() val lat = strs[0].toDouble() val lng = strs[1].toDouble() startlocation = LatLng(lat, lng) Log.e("RoutendarstellungActivity", "Fatal $lat & $lng") } catch (e: Exception) { // 请求失败、格式解析错误就用默认坐标 e.printStackTrace() } // 切主线程操作地图 withContext(Dispatchers.Main) { mMap.addMarker(MarkerOptions().position(startlocation).title("Marker in Würzburg")) mMap.moveCamera(CameraUpdateFactory.newLatLng(startlocation)) } } }
几个要注意的点
- 不要手动创建
CoroutineScope(Dispatchers.IO)这种无绑定的协程,在Activity里优先用lifecycleScope,不会出现页面退了之后协程还在跑、空指针崩溃的问题 - 挂起函数(比如这里Firebase的
await())会自动等待异步任务返回,不会卡主线程,写起来和同步代码逻辑一致,不需要嵌套多层回调 - 网络请求、数据解析都要加异常捕获,失败的时候走兜底逻辑,避免APP直接崩溃
内容的提问来源于stack exchange,提问作者Featch
相关产品推荐
相关产品推荐

