如何在单独的存储库(MVVM)中传递 Firestore SnapshotListener 提供的实时数据

How to pass through livedata provided by Firestore SnapshotListener in a separate repository (MVVM)

经过几个小时的尝试和搜索,我仍然卡住了,希望有人能帮助我。 我试图通过我的 ViewModel 从 Firestore(使用 SnapshotListener)获取实时更新到我的 Activity,但我的所有尝试都失败了。以下是我当前的设置 - 尝试更新我的存储库中的 LiveData 并将其移交给视图模型...

我的问题: 我的 Firestore 集合中有 UserData(在文档中)。我尝试使用 observeUserData() 函数在运行时监听当前用户的变化。此函数提供的数据(关于文档更改)应通过我的 ViewModel 发送到我的 Activiy。如果我在 Firestore 中更改我的用户文档,SnapshotListener 会按预期触发,但更新没有到达我的 ViewModel,因此没有到达我的 Activity.

有人能帮我存档吗?我现在看到的唯一解决方案是在我的 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

class MyViewModel (private val uid : String) : ViewModel() {
    private var _userData = MutableLiveData<UserData>()
    val userData: LiveData<UserData> = _userData

    fun getUserData() {
        Log.d(TAG, "getUserData called")
        FirestoreService.observeUserData(uid)
        var data = FirestoreService.userDataLiveData
        _userData = data
    }
}

Activity

//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
}

发出实时数据的实现可能如下:

class FirestoreServiceImpl : FireStoreService {
    val db = FirebaseFirestore.getInstance()

    fun sendUserData(uid: String): LiveData<String> = liveData {
        val mySnapshot = db.collection("userData)".document(userId).await()
        emit(mySnapshot?.toUserData)
    }
}

如果想在viewModel中调用这个方法,最好把LiveData改成Flow

fun sendUserData(uid: String): Flow<String> = flow {
    val mySnapshot = db.collection("userData)".document(userId).await()
    emit(mySnapshot?.toUserData)
}

在您的 ViewModel 中,您可以这样做:

val myInput = "TestUUID"

val myUserID = sendUserData(myInput).asLiveData()

然后,最后在片段/activity:

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

谢谢大家的回复 - 幸运的是我在这个问题上找到了问题。

我想我混淆了太多来自不同“指南”/“方法”的东西 - 幸运的是我在下面找到了 Doug Stevenson 的精彩课程,这让我摆脱了这个:

https://www.youtube.com/watch?v=WXc4adLMDqk

谢谢道格 :)