使用 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()
添加观察者(并在第一次调用后将其删除)可以工作。确实不确定这是否是最好的方法。
我假设您有另一个类,例如 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,这可能是你的问题。
在您的代码中,您向 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
我知道这些并不是您可以实施的所有最佳实践,但这些是我见过的
我希望这有帮助,如果您遇到任何问题,请告诉我