Firestore Kotlin创建坐标嵌套数组遇空值问题求助
解决Firestore异步回调导致外部数组为空的问题
兄弟,你这是踩中了异步操作的经典陷阱!我来给你掰扯清楚:
Firestore的get()方法是异步执行的——它不会卡在那里等服务器返回数据,而是直接继续往下跑后面的代码。所以你的代码执行顺序其实是这样的:
- 发起Firestore的获取请求
- 立刻执行监听器外面的
println,这时候posiciones还没被填充,自然是空数组 - 等服务器把数据传回来后,才会触发
addOnSuccessListener里的循环,把数据加到数组里
说白了就是:你打印的时机太早了,数组还没来得及被赋值呢!
给你三种常见的解决方案:
方案1:把逻辑挪到回调内部(最简单直接)
既然数据只有在回调里才准备好,那所有需要用这个数组的代码都放到addOnSuccessListener里面就行:
myDB.collection("players") .get() .addOnSuccessListener { result -> for (document in result) { posiciones.add( arrayOf( document.get("posx").toString(), document.get("posy").toString() ) ) } // 在这里使用数组,打印或者传给其他函数都没问题 println("Testing: " + posiciones) updateUIWithPositions(posiciones) // 比如更新UI的逻辑 } .addOnFailureListener { exception -> Log.d(ContentValues.TAG, "Error getting documents: ", exception) }
方案2:用Kotlin协程让代码“看起来同步”(更优雅)
如果不想把代码都塞在回调里,用协程可以让异步代码写得像同步一样。首先确保你加了协程依赖(在build.gradle里):
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3" // 版本可以用最新的
然后在Activity里用lifecycleScope(避免内存泄漏)来执行:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) lifecycleScope.launch { try { // 用await()等待Firestore返回结果 val result = myDB.collection("players").get().await() for (document in result) { posiciones.add( arrayOf( document.get("posx").toString(), document.get("posy").toString() ) ) } // 这里可以安全使用数组了 println("Testing: " + posiciones) } catch (exception: Exception) { Log.d(ContentValues.TAG, "Error getting documents: ", exception) } } }
方案3:自定义回调接口(适合复用场景)
如果这个获取位置的逻辑要在多个地方用,可以封装成带回调的函数:
先定义一个回调接口:
interface PositionsCallback { fun onSuccess(positions: ArrayList<Array<String>>) fun onFailure(error: Exception) }
然后写获取数据的函数:
fun fetchPlayerPositions(callback: PositionsCallback) { myDB.collection("players") .get() .addOnSuccessListener { result -> val positions = ArrayList<Array<String>>() for (document in result) { positions.add( arrayOf( document.get("posx").toString(), document.get("posy").toString() ) ) } callback.onSuccess(positions) } .addOnFailureListener { exception -> callback.onFailure(exception) } }
最后在onCreate里调用:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) fetchPlayerPositions(object : PositionsCallback { override fun onSuccess(positions: ArrayList<Array<String>>) { println("Testing: " + positions) // 在这里处理数据 } override fun onFailure(error: Exception) { Log.d(ContentValues.TAG, "Error getting documents: ", error) } }) }
总结一下
核心就是记住:Firestore的所有网络请求都是异步的,依赖返回数据的逻辑必须等数据回来后再执行——要么塞在回调里,要么用协程/自定义回调来处理,绝对不能在请求外面直接同步使用还没被赋值的变量!
内容的提问来源于stack exchange,提问作者Puntogris
相关产品推荐
相关产品推荐

