我的问题是,当我尝试从数据库中获取文档时,这个文档(即对象)总是为空。只有在使用Kotlin协程从数据库中获取文档时才会出现这个问题。使用带有监听器的标准方法可以正常工作。
EmailRepository
interface EmailRepository {
suspend fun getCalibratePrice(): Flow<EmailEntity?>
suspend fun getRepairPrice(): Flow<EmailEntity?>
}
EmailRepository实现
class EmailRepositoryImpl @Inject constructor(private val db: FirebaseFirestore) : EmailRepository {
fun hasInternet(): Boolean {
return true
}
// This works! When using flow to write a document, the document is written!
override fun sendEmail(email: Email)= flow {
emit(EmailStatus.loading())
if (hasInternet()) {
db.collection("emails").add(email).await()
emit(EmailStatus.success(Unit))
} else {
emit(EmailStatus.failed<Unit>("No Email connection"))
}
}.catch {
emit(EmailStatus.failed(it.message.toString()))
}.flowOn(Dispatchers.Main)
// This does not work! "EmailEntity" is always null. I checked the document path!
override suspend fun getCalibratePrice(): Flow<EmailEntity?> = flow {
val result = db.collection("emailprice").document("Kalibrieren").get().await()
emit(result.toObject<EmailEntity>())
}.catch {
}.flowOn(Dispatchers.Main)
// This does not work! "EmailEntity" is always null. I checked the document path!
override suspend fun getRepairPrice(): Flow<EmailEntity?> = flow {
val result = db.collection("emailprice").document("Reparieren").get().await()
emit(result.toObject<EmailEntity>())
}.catch {
}.flowOn(Dispatchers.Main)
}
获取数据的Viewmodel
init {
viewModelScope.launch {
withContext(Dispatchers.IO) {
if (subject.value != null){
when(subject.value) {
"Test" -> {
emailRepository.getCalibratePrice().collect {
emailEntity.value = it
}
}
"Toast" -> {
emailRepository.getRepairPrice().collect {
emailEntity.value = it
}
}
}
}
}
}
}
private val emailEntity = MutableLiveData<EmailEntity?>()
private val _subject = MutableLiveData<String>()
val subject: LiveData<String> get() = _subject
片段
@AndroidEntryPoint
class CalibrateRepairMessageFragment() : EmailFragment<FragmentCalibrateRepairMessageBinding>(
R.layout.fragment_calibrate_repair_message,
) {
// Get current toolbar Title and send it to the next fragment.
private val toolbarText: CharSequence by lazy { toolbar_title.text }
override val viewModel: EmailViewModel by navGraphViewModels(R.id.nav_send_email) { defaultViewModelProviderFactory }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Here I set the data from the MutableLiveData "subject". I don't know how to do it better
viewModel.setSubject(toolbarText.toString())
}
}
有人可能会认为Firebase规则是问题所在,但在这里不应该是这种情况,因为数据库是开放的,并且使用监听器方法确实可行。
我从CalibrateRepairMessageFragment
获取subject.value
。当我不检查if(subject.value != null)
时,我会从我的init
块中获得一个NullPointerException。
我只会在我的viewModel中使用emailEntitiy
,而不会在它之外使用。
我感激任何帮助,谢谢。
编辑
这是我获取数据的新方式。对象仍然为空!我还在我的挂起函数中添加了Timber.d
消息,但这些消息也从未被执行,因此flow从未抛出错误...使用这种新方法,我不再收到NullPointerException。
private val emailEntity = liveData {
when(subject.value) {
"Test" -> emailRepository.getCalibratePrice().collect {
emit(it)
}
"Toast" -> emailRepository.getRepairPrice().collect {
emit(it)
}
// Else block is never executed, therefore "subject.value" is either Test or toast and the logic works. Still error when using flow!
else -> EmailEntity("ERROR", 0F)
}
}
在我的一个函数中,我使用 Timber.d(“EmailEntity is ${emailEntity.value}”)
检查emailEntity
是否为空。
然后我使用 val price = MutableLiveData(emailEntity.value?.basePrice ?: 1000F)
设置价格,但由于emailentity
是null
,因此价格始终为1000。
编辑2
我现在进一步研究了这个问题并取得了重大进展。当从像CalibrateRepairMessageFragment
这样的片段观察emailEntity
时,值不再是null
。
此外,在观察emailEntity
时,值也不再是null
,但仅在一个片段中观察时如此!那么我该如何从我的viewModel
观察emailEntity
或从我的repository
获取值并在我的viewmodel
中使用它?