如何在 Jetpack 组合文本视图中显示 Firestore 集合文档中的文档字段

How can show a document field from a Firestore collection document in a jetpack compose text view

如果我违反了一些规则,或者之前已经有人问过,我感到非常抱歉。我花了很多时间来 google 示例,以及有关堆栈溢出和其他资源的问题。但我根本无法理解如何从 firestore 集合中获取文档字段,并在 Jetpack 撰写文本函数中显示字符串值。

我是编程初学者,Android。所以我确实对我应该怎么做有一些根本性的误解,但这是我的尝试,但没有用,我不明白为什么。

在 Firestore 中,我有一个名为 users 的集合,其中包含一个名为 holidaySavings 的文档,其中有一个名为 name 的字符串类型的字段。

我想在可组合的文本函数中显示名称的值。

我有一个名为 storedData 的 class 来处理 Firestore。它具有创建和更新集合/文档/字段的方法。行得通。

但我似乎无法将文档中的字段值读取到 Jetpack 可组合文本中。

我可以从文档字段中读取值,然后登录 Android studio。

这是我在 class 中处理 Firestore 数据库的功能

fun readDataTestFinal(): String{
        val docRef = db.collection("users").document("holidaySavings")
        var returnTest = ""
        docRef.get()
            .addOnSuccessListener { document ->
                if (document != null) {
                    Log.d("Rtest", "DocumentSnapshot data: ${document.data}")

                    // I want to return this so I can use it in a composable text view
                    returnTest = document.get("name").toString()
                } else {
                    Log.d("Rtest", "No such document")
                }
            }
            .addOnFailureListener {  exception ->
                Log.d("Rfail", "get failed with ", exception)
            }
        return returnTest
    }

在这里,我尝试将值读入 jetpack compose Text 函数。

var newStringFromStoredData by remember {
                mutableStateOf(storedData().readDataTestFinal())
            }
            Text(
                modifier = Modifier.background(color = Color.Blue),
                text = newStringFromStoredData
            )

当我 运行 应用程序时。一切都编译得很好,我从文档字段中得到了很好的值,并且可以在 Android Studio 的登录中看到它。

但是 Compose 函数在调用 Text 时没有在屏幕上显示值 newStringFromStoredData?

谁能告诉我我不明白的是什么,以及如何才能使用 firestore 文档字段并在 Jetpack Compose Text 函数中显示值?

Firebase 调用是异步的,这意味着它不会立即 return 数据。这就是 API 使用回调的原因。因此,您的函数 readDataTestFinal 始终是 return 一个空字符串。

您可以使用的一种解决方案是将您的函数转换为 suspend 函数并使用协程作用域调用它。例如:

suspend fun readDataTestFinal(): String {
    val docRef = firestore.collection("users")
        .document("holidaySavings")
    return suspendCoroutine { continuation ->
        docRef.get()
            .addOnSuccessListener { document ->
                if (document != null) {
                    continuation.resume(document.get("name").toString())
                } else {
                    continuation.resume("No such document")
                }
            }
            .addOnFailureListener { exception ->
                continuation.resumeWithException(exception)
            }
    }
}

在上面的代码中,我们正在转换一个

在您的可组合项中,您可以执行以下操作:

var newStringFromStoredData by remember {
    mutableStateOf("")
}
Text(newStringFromStoredData)

LaunchedEffect(newStringFromStoredData) {
    newStringFromStoredData =
        try { readDataTestFinal() } catch(e: Exception) { "Error!" }
}

LaunchedEffect 将启动您的暂停功能并在加载后立即更新结果。

更好的选择是在视图模型中定义此调用并从中调用此函数。但我认为这回答了你的问题,你可以稍后改进你的架构。您可以从 here.

开始

最方便、最快且显然是 best-in-your-case 补丁是使用所谓的 valueEventListeners

Firebase 为您提供了这些有用的方法,以便您可以将应用程序的数据 up-to-date 保存在 Firebase 服务器上。

val docRef = db.collection("cities").document("SF")
docRef.addSnapshotListener { snapshot, e -> // e is for error

    // If error occurs
    if (e != null) {
        Log.w(TAG, "Listen failed.", e)
        return@addSnapshotListener
    }
    
    // If backend value not received, use this to get current local stored value
    val source = if (snapshot != null && snapshot.metadata.hasPendingWrites())
        "Local"
    else
        "Server"
    
    // If request was successful, 
    if (snapshot != null && snapshot.exists()) {
        Log.d(TAG, "$source data: ${snapshot.data}")
        //Update your text variable here
        newStringFromStoredData = snapshot.data // Might need type-conversion
    } else {
        Log.d(TAG, "$source data: null")
    }
}

这不仅可以解决您在问题中描述的问题,而且还可以确保只要服务器上的值为 changed/updated,您的文本就会随之更新。使用这些侦听器通常是一个很好的最佳实践,并且这些侦听器通常会转换为 LiveData 对象以遵守 'separation-of-concerns' 原则,但是您可以使用这个简单的实现来描述简单的 use-case .

另一件事,这通常会出现在 viewModel 中,因此,您也应该在 viewmodel 中声明文本变量。 在 init 块中尝试。

calss MVVM: ViewModel() {
  init {
    /* Paste Code From Above Here */
  }

  var newStringFromStoredData by mutableStateOf("") 

}

然后在 Composable 中阅读它

Text(viewModel.newStringFromStoredData)