如何使用 LiveData 检索视图模型中的数据库数据

问题描述 投票:0回答:1

使用 Firebase Auth 成功登录后,我的 Fragment 会收到当前用户详细信息。有了这些,我想查找具有相同用户 ID 的现有数据库记录,如果不存在,则保留它。

我的片段

private fun onSignInResult(result: FirebaseAuthUIAuthenticationResult) {
    if (result.resultCode == AppCompatActivity.RESULT_OK) {
        FirebaseAuth.getInstance().currentUser?.let {
            viewModel.setFirebaseUser(it)
        }
        findNavController().navigate(SignInFragmentDirections.navSignInToHome())
    }
}

视图模型

class UserViewModel(
    private val usersRepository: UsersRepository
    ) : ViewModel() {

    private val currentUser: MutableLiveData<User> = MutableLiveData()

    fun setFirebaseUser(fireBaseUser: FirebaseUser) {
        with (fireBaseUser) {
            currentUser.value = User(uid, email, displayName)
            usersRepository.getUser(uid).let {
                if (it.value != null) {
                    Log.i("UserViewModel", "User Found")
                    currentUser.value = it.value
                } else {
                    viewModelScope.launch {
                        Log.i("UserViewModel", "Coroutine scope")
                        val user = User(uid, email, displayName)
                        usersRepository.insertUser(user)
                        currentUser.value = user
                    }
                }
            }
        }
    }
}

用户存储库

interface UsersRepository {
    fun getUser(id: String): LiveData<User?>
}

此代码实际上有效,但在第二次或连续登录后,永远找不到现有用户,并且始终执行

usersRepository#insertUser()
函数,这是由于
usersRepository#getUser()
始终返回空用户造成的。 我认为这是因为我没有正确观察 LiveData 对象,但我不确定应该如何在视图模型中观察它。

在回答之前,请注意,我想学习可能仅使用 kotlin 的最佳实践 - jetpack 库 Room、LiveData、ViewModel(无 RxJava 或其他 DI 模块)。

我是否应该将逻辑移至 Fragment 中以便可以观察 LiveData 对象?或者存储库应该返回用户而不是 LiveData?


编辑: 使用

repoUser.observeForever()
添加观察者(并在第一次调用后将其删除)可以工作。确实不确定这是否是最好的方法。

参考: 从 ViewModel 观察 LiveData

android kotlin android-room android-jetpack android-livedata
1个回答
0
投票

首先

我假设您有另一个类,例如 UserRepositoryImpl,您在其中实现了接口中的功能,但您忘记包含它。

如果没有的话在哪里实现这些功能

这是实现 getUser fun 的示例

fun getUser(id:String):LiveData<User> {
    val userData = MutableLiveData<User>()
    Firestore.collection(Constants.USER_COLLECTION)
    .whereEqualTo("id",id)
    .addSnapshotListener{value,error ->
    
        if(error != null){
          Log.e(TAG,error.getMessage())  
          return@SnapshotListener
        }
        
        for(documentSnapshot in value.documents){
            val user = documentSnapshot.toObject(User::class.java)
            
            userData.value = user
        }
        
    }
    
    return userData
}

然后你可以像以前一样在视图模型中获取它

usersRepository.getUser(uid).let {
                if (it.value != null) {
                    Log.i("UserViewModel", "User Found")
                    currentUser.value = it.value
                } else {
                    viewModelScope.launch {
                        Log.i("UserViewModel", "Coroutine scope")
                        val user = User(uid, email, displayName)
                        usersRepository.insertUser(user)
                        currentUser.value = user
                    }
                }
            }

重要检查firesotre中的读取和写入权限规则,如果它们设置为false,则将它们设置为true,这可能是你的问题。


最佳实践

  • 使用 dagger hilt Dagger hilt 是一个依赖注入库,你可以在这里了解更多信息 相信我,这会让事情变得更容易
  • 不要向用户界面公开可变的实时数据

在您的代码中,您向 ui 公开了可变的实时数据以进行观察,这不好,因为 ui 不应该以任何方式编辑数据,它唯一的建议是显示数据并将 ui 事件发送到视图模型

因此,将实时数据添加到视图模型的更好方法如下

   // This is the one that will be edited in the view model
 private val _currentUser: MutableLiveData<User> = MutableLiveData()
// This is the one that the ui will observe
  val currentUser get() = _currentUser

我知道这些并不是您可以实施的所有最佳实践,但这些是我见过的


我希望这有帮助,如果您遇到任何问题,请告诉我

© www.soinside.com 2019 - 2024. All rights reserved.