【问题标题】:Firebase: How to check if document write was successfulFirebase:如何检查文档写入是否成功
【发布时间】:2020-09-16 14:46:22
【问题描述】:

我想检查我的数据库写入是否成功,以便向用户显示错误消息。

我目前的方法不起作用,因为它说“类型不匹配,找到所需的单元 EmailStatus”

目前的做法

class EmailRepositoryImpl : EmailRepository {
    private val db = Firebase.firestore

    override fun sendEmail(email: Email): EmailStatus<Nothing> {
        db.collection("emails").document().set(email).addOnCompleteListener {
            if (it.isSuccessful) return@addOnCompleteListener EmailStatus.Success<Nothing>
            if (it.isCanceled) return@addOnCompleteListener EmailStatus.Error(it.exception!!)
        }
    }
}

状态密封类

sealed class EmailStatus<out T> {
    data class Success<out T>(val data: T) : EmailStatus<T>()
    data class Error(val exception: Exception) : EmailStatus<Nothing>()
}

甚至可以写出这样的东西吗?据我所知,有一个通用的firebase error type,但我没有找到任何与 kotlin 或 android 相关的东西......

感谢大家的帮助,谢谢

编辑

我尝试获取我的文档,但我只是得到空值:(当我使用侦听器方法时,一切正常)

界面

interface EmailRepository {
    suspend fun getEmail(): Flow<EmailEntity?>
}

接口实现

override suspend fun getEmail(): Flow<EmailEntity?> = flow {
    val result = db.collection("emailprice").document("Email").get().await()
    emit(result.toObject<EmailEntity>())
}

视图模型

private val emailEntity = liveData<EmailEntity?>(Dispatchers.IO) {
    emailRepository.getCalibratePrice()
}

【问题讨论】:

    标签: android firebase kotlin google-cloud-firestore sealed-class


    【解决方案1】:

    问题是addOnCompleteListener 回调没有返回任何东西(单位),而您正试图从该范围返回EmailStatus

    你有三种方法:

    1. 创建一个接口,该接口将填充该值并将该 EmailStatus 返回到您的调用者层
    2. 当对 firebase 的异步调用完成时,使用 Coroutines 暂停此函数,然后返回该值
    3. 当数据准备好处理时,使用 Flow 提供数据

    我认为做这个一次性操作最简单的方法是使用协程;我写了an article about that

    【讨论】:

    • 非常感谢您的快速回复。但是我有一个问题:由于我没有从 Firebase 获取任何数据而是写入它,我怎么知道这个写入成功并因此发出 Resource.Sucess?
    • @Andrew 您不能立即从函数返回成功值,因为 Firebase API 是异步的,并且会在操作完成之前立即返回。您必须在此处的答案中选择一个选项。
    • 好的,谢谢。我已经实现了文章中的方法,现在我的文档是“LiveData>”。如何获取 Viewmodel 内部的 EmailEntity 数据以使用它?
    • LiveData 的问题是你现在将 livedata 附加到你的存储库,这并不是真正建议的,你可以做的是用我上面分享的帖子实现协程,在那里你可以使用 google- play-services-coroutine 库对 Firebase 中的任何异步工作执行 .await()
    • @GastonSailen 好的,谢谢。我已经这样做了,但我只得到空值。我将对此进行调查。
    【解决方案2】:

    好的,这是最终的解决方案,感谢@Gastón Saillén 和@Doug Stevenson:

    电子邮件存储库

    interface EmailRepository {
        fun sendEmail(email: Email): Flow<EmailStatus<Unit>>
    }
    

    EmailRepository 实现

    class EmailRepositoryImpl @Inject constructor(
        private val db: FirebaseFirestore
    ) : EmailRepository {
    
        override fun sendEmail(email: Email)= flow<EmailStatus<Unit>> {
            db.collection("emails").add(email).await()
            emit(EmailStatus.success(Unit))
        }.catch {
            emit(EmailStatus.failed(it.message.toString()))
        }.flowOn(Dispatchers.Main)
    
    }
    

    视图模型

    fun sendEmail(): LiveData<EmailStatus<Unit>> {
        val newEmail = createEmail()
        return emailRepository.sendEmail(newEmail).asLiveData()
    }
    

    片段

    btn.setOnClickListener {
                viewModel.sendEmail().observe(viewLifecycleOwner) {
                    when(it) {
                        is EmailStatus.Success -> {
                            valid = true
                            navigateTo(next, bundleNext)
                            Toast.makeText(requireContext(), "Success", Toast.LENGTH_SHORT).show()
                        }
                        is EmailStatus.Failure -> {
                            valid = false
                            Toast.makeText(requireContext(), "Failed ${it.message}", Toast.LENGTH_SHORT).show()
                        }
                    }
                }
    }
    

    我目前唯一的问题是我的“失败状态”不能正常工作。

    如果用户无法访问互联网,它应该会失败。目前,对数据库的写入永远不会失败,Firebase 只会等到用户可以访问互联网。这里的问题是,当我点击多次时,写入会执行多次。但是我想我必须在这里实现更多的逻辑,上面写的代码和现在一样很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 2013-03-10
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多