问题描述
我当前的方法无效,因为它显示“类型不匹配,找到了必需的单位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>())
}
viewmodel
private val emailEntity = liveData<EmailEntity?>(dispatchers.IO) {
emailRepository.getCalibratePrice()
}
解决方法
问题是addOnCompleteListener
回调不返回任何内容(单位),而您试图从该范围返回EmailStatus
。
您有三种方法:
- 创建一个界面,该界面将填充值并将该EmailStatus返回到您的呼叫者层
- 在完成对Firebase的异步调用后,使用协程暂停此功能,然后返回该值
- 在准备好处理时使用Flow提供数据
我认为完成这一步操作的最简单方法是使用协程。我写了an article about that。
,好吧,这是最终的解决方案,这要感谢@GastónSaillén和@Doug Stevenson:
EmailRepository
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)
}
ViewModel
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()
}
}
}
}
我目前唯一的问题是我的“ faield状态”无法正常工作。
如果用户无法访问互联网,则应该失败。当前,写入数据库永远不会失败,Firebase会一直等到用户可以访问Internet。这里的问题是,当我单击多次时,写入将执行多次。但是我想我必须在这里实现更多的逻辑,并且上面编写的代码像现在一样很好。