You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Firebase数据库返回读取值?附代码正确性疑问

问题

我有一段Kotlin代码,用于从Firebase Firestore读取用户的姓名:

fun readNameSurnameByEmail(email: String): String {

    // 从数据库读取除密码外的所有数据,每个功能单独写函数,参数为邮箱
    val database = FirebaseFirestore.getInstance()

    val myRef = database.collection("Users").document(email)

    myRef.get()
        .addOnSuccessListener { document ->
            if (document != null) {
                val fieldValue = document.get("name_surname") as String
                Log.d(TAG, "姓名读取成功")
            } else {
                Log.d(TAG, "文档为空")
            }
        }
        .addOnFailureListener { exception ->
            if (exception is FirebaseFirestoreException) {
                Log.e(TAG, "获取文档出错: ", exception)
            }
        }

}

我在addOnSuccessListener里创建了fieldValue,请问如何返回它?另外,通过文档名称(邮箱)获取字段值的方式是否正确?

之后我更新了代码,请问这样写是否正确?

fun readNameSurnameByEmail(email: String): String {

    // 从数据库读取除密码外的所有数据,每个功能单独写函数,参数为邮箱
    val database = FirebaseFirestore.getInstance()

    val myRef = database.collection("Users").document(email)

    var fieldValue = ""
    
    myRef.get()
        .addOnSuccessListener { document ->
            if (document != null) {
                fieldValue = document.get("name_surname") as String
                Log.d(TAG, "姓名读取成功")
            } else {
                Log.d(TAG, "文档为空")
            }
        }
        .addOnFailureListener { exception ->
            if (exception is FirebaseFirestoreException) {
                Log.e(TAG, "获取文档出错: ", exception)
            }
        }
    return fieldValue
}

解答

1. 通过文档名称获取字段的方式是正确的

Firestore里collection("Users").document(email)的写法没问题,只要你的用户文档确实是用邮箱作为文档ID存储的,这种直接通过文档ID定位文档的方式高效且符合规范。

2. 关于返回fieldValue的问题

你更新后的代码不正确,核心问题是Firestore的get()是异步操作:

  • 调用myRef.get()后,代码会立刻跳到return fieldValue执行,此时addOnSuccessListener里的逻辑还没跑,返回的只是初始的空字符串"",根本拿不到数据库里的真实数据。

正确的解决方式

在Kotlin里处理Firestore异步请求,常用几种方案:

方案一:使用回调函数

定义一个回调接口,在成功获取数据后触发回调返回结果:

// 定义回调接口
interface OnNameSurnameLoadedListener {
    fun onSuccess(nameSurname: String)
    fun onFailure(error: Exception)
}

fun readNameSurnameByEmail(email: String, listener: OnNameSurnameLoadedListener) {
    val database = FirebaseFirestore.getInstance()
    val myRef = database.collection("Users").document(email)

    myRef.get()
        .addOnSuccessListener { document ->
            if (document != null && document.exists()) { // 建议加document.exists()判断文档是否存在
                val fieldValue = document.getString("name_surname") ?: "" // 用getString避免强转,同时处理null
                listener.onSuccess(fieldValue)
                Log.d(TAG, "姓名读取成功")
            } else {
                listener.onFailure(IllegalArgumentException("文档不存在或为空"))
                Log.d(TAG, "文档不存在或为空")
            }
        }
        .addOnFailureListener { exception ->
            listener.onFailure(exception)
            Log.e(TAG, "获取文档出错: ", exception)
        }
}

// 调用示例
readNameSurnameByEmail("user@example.com", object : OnNameSurnameLoadedListener {
    override fun onSuccess(nameSurname: String) {
        // 在这里处理拿到的姓名
    }

    override fun onFailure(error: Exception) {
        // 处理错误情况
    }
})

方案二:使用Kotlin协程(推荐)

借助Firestore的协程扩展(需添加依赖),可以用同步写法处理异步操作:
先添加依赖(在build.gradle中):

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3"

然后把函数改成挂起函数:

import kotlinx.coroutines.tasks.await

suspend fun readNameSurnameByEmail(email: String): String? {
    return try {
        val database = FirebaseFirestore.getInstance()
        val myRef = database.collection("Users").document(email)
        val document = myRef.get().await() // 等待异步操作完成
        if (document.exists()) {
            document.getString("name_surname")
        } else {
            Log.d(TAG, "文档不存在")
            null
        }
    } catch (e: FirebaseFirestoreException) {
        Log.e(TAG, "获取文档出错: ", e)
        null
    }
}

// 调用示例(必须在协程作用域内)
CoroutineScope(Dispatchers.IO).launch {
    val nameSurname = readNameSurnameByEmail("user@example.com")
    // 切换到主线程更新UI等操作
    withContext(Dispatchers.Main) {
        // 处理结果
    }
}

补充提示

  • 尽量避免用as String强转,推荐用document.getString("name_surname"),它会返回String?,能安全处理字段不存在的情况。
  • 建议加上document.exists()判断,区分“文档不存在”和“文档为空”两种场景。

内容的提问来源于stack exchange,提问作者real4you

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 05:10:42