Android 如何在单独的存储库(MVVM)中传递Firestore SnapshotListener提供的livedata

Android 如何在单独的存储库(MVVM)中传递Firestore SnapshotListener提供的livedata,android,kotlin,google-cloud-firestore,android-livedata,android-mvvm,Android,Kotlin,Google Cloud Firestore,Android Livedata,Android Mvvm,经过几个小时的努力和搜寻,我仍然被困在那里,希望有人能帮助我。 我试图通过ViewModel从Firestore(使用SnapshotListener)获取活动的实时更新,但所有尝试都失败了。下面是我当前的设置-尝试更新存储库中的LiveData并将其移交给视图模型 我的问题是: 我的Firestore集合中有UserData(在文档中)。我尝试使用observeUserData()函数在运行时侦听对当前用户的更改。此功能提供的数据(文档更改时)应通过my ViewModel发送到my Acti

经过几个小时的努力和搜寻,我仍然被困在那里,希望有人能帮助我。 我试图通过ViewModel从Firestore(使用SnapshotListener)获取活动的实时更新,但所有尝试都失败了。下面是我当前的设置-尝试更新存储库中的LiveData并将其移交给视图模型

我的问题是: 我的Firestore集合中有UserData(在文档中)。我尝试使用observeUserData()函数在运行时侦听对当前用户的更改。此功能提供的数据(文档更改时)应通过my ViewModel发送到my Activity。如果我对Firestore中的用户文档更改了某些内容,SnapshotListener将按预期启动,但更新未到达我的ViewModel,因此未到达我的活动

有人能帮我存档吗?我现在看到的唯一解决方案是在我的ViewModel中添加SnapshotListener,但据我所知,这是一种糟糕的做法? 多谢各位

Firestore存储库

object FirestoreService {    
    val db = FirebaseFirestore.getInstance()
    val userDataLiveData = MutableLiveData<UserData>()


    fun observeUserData(userId: String) {
        try {
            db.collection("userData").document(userId).addSnapshotListener{ documentSnapshot: DocumentSnapshot?, firebaseFirestoreException: FirebaseFirestoreException? ->
                firebaseFirestoreException?.let {
                    Log.e(TAG, firebaseFirestoreException.toString())
                    return@addSnapshotListener
                }

                val data = documentSnapshot?.toUserData()

                data?.let {
                    Log.d(TAG, "post new value")
                    userDataLiveData.postValue(data)
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error getting user data", e)
        }
    }
//ViewModel Setup
val factory = MyViewModelFactory(user.uid.toString())
val viewModel = ViewModelProvider(this, factory).get(MyViewModel::class.java)

//Initialize UserData
viewModel.getUserData()
viewModel.userData.observe(this, Observer {
    userData = it
    Log.d(TAG, userData.toString())
})

您需要首先初始化viewModel

lateinit var userViewModel : MyViewModel

userViewModel = new ViewModelProvider(this).get(MyViewModel::class.java)
然后在userViewModel上使用getViewLifeCycleOwner方法,然后观察将包含userDataModel的LiveData


onChanged()方法可以访问userDataModel中的方法(getter和setter)

有一种更简单的方法,无需任何侦听器。首先,添加此依赖项:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.9"
然后假设您拥有以下存储库:

inteface FirestoreService {
    fun sendUserData(uid: String): LiveData<String> // Or whatever it should emit
}
在ViewModel中,您可以执行以下操作:

val myInput = "TestUUID"

val myUserID = sendUserData(myInput).asLiveData()
最后,在片段/活动中:

yourViewModel.myUserID.observe(viewLifecycleOwner) {
   // do stuff here
} 

谢谢大家的回复,幸运的是我发现了这个问题

我想我从不同的“指南”/“方法”中混淆了太多的东西-幸运的是,我在下面找到了道格·史蒂文森精彩的演讲,这让我摆脱了困境:


谢谢你,道格:)

请编辑问题,更详细地解释这里的代码没有按你期望的方式工作。仅仅说它不起作用是不够的,我们需要调试信息。我建议阅读:嗨,道格,谢谢你的回复。我的Firestore集合中有UserData。我尝试使用observeUserData()函数在运行时侦听对当前用户的更改。此功能提供的数据(文档更改时)应通过my ViewModel发送到my Activity。如果我在Firestore中对我的用户更改了某些内容,SnapshotListener将启动,但是更新没有到达我的ViewModel,因此没有到达我的活动。嘿,Damola,谢谢你的回复。我已经在活动中初始化了ViewModel,只是错过了片段。将在上面编辑我的帖子://ViewModel Setup val factory=MyViewModelFactory(uid)val ViewModel=ViewModelProvider(这个,factory)。get(MyViewModel::class.java)嘿,安德鲁,我更新了我的协同程序播放服务-出于某种原因,它是在版本1.1.1-但不幸的是,这没有帮助。不太理解接口和实现部分的建议,仅仅对象是不够的吗?我的原始帖子中的“FirestoreService”对象是整个类。您关于sendUserData的建议听起来很有趣,但对于上述实现,我在调用函数时只会收到一次文档-但我想在Firestore中对文档更改进行“实时更新”-您知道如何存档吗?@Sebastian您说得对,我错过了这一部分,抱歉。正如它所展示的,我会提到如何通过协同程序实现实时侦听器。嗨,安德鲁,谢谢。我尽量避免在ViewModel中调用数据库,因为(如果我理解正确,对MVVM体系结构来说是非常新的),我不应该混淆数据库和ViewModel部分——或者在这一点上我错了吗?我只是想知道。。。如果我只想获得一个文档/值,我的设置就可以了。我就是无法让这些更新生效。这家伙的演示题为“Firebase和Android Jetpack:像手套一样合身”。这是完全相反的。我是唯一一个觉得这件事过于复杂和复杂的人吗?
fun sendUserData(uid: String): Flow<String> = flow {
    val mySnapshot = db.collection("userData)".document(userId).await()
    emit(mySnapshot?.toUserData)
}
val myInput = "TestUUID"

val myUserID = sendUserData(myInput).asLiveData()
yourViewModel.myUserID.observe(viewLifecycleOwner) {
   // do stuff here
}