首页 > 解决方案 > 使用 ViewModel 和 LiveData 时如何设置 Firebase 实时数据库的子值?

问题描述

我有以下内容data class,其中包含 Firebase 实时数据库中特定引用的子值:

data class Users(
    val uid: String = "",
    var firstName: String = "",
    var lastName: String = "",
)

这是我的ViewModel

class UsersViewModel : ViewModel() {
    private val uid = Firebase.auth.currentUser!!.uid
    private val USERS_REF: DatabaseReference = FirebaseDatabase.getInstance().getReference("/users/$uid")
    private val liveData: FirebaseQueryLiveData = FirebaseQueryLiveData(USERS_REF)
    private val usersLiveData: MediatorLiveData<Users> = MediatorLiveData()

    init {
        usersLiveData.addSource(liveData, object : Observer<DataSnapshot> {
            override fun onChanged(dataSnapshot: DataSnapshot?) {
                if (dataSnapshot != null) {
                    usersLiveData.postValue(dataSnapshot.getValue(Users::class.java))
                } else {
                    usersLiveData.value = null
                }
            }
        })
    }

    @NonNull
    fun getUsersLiveData() : LiveData<Users> {
        return usersLiveData
    }
}

这是我的扩展LiveData

class FirebaseQueryLiveData(ref: DatabaseReference) : LiveData<DataSnapshot>() {
    private val query: Query = ref
    private val listener: MyValueEventListener = MyValueEventListener()
    private var listenerRemovePending = false

    private val removeListener = object : Runnable {
        override fun run() {
            query.removeEventListener(listener)
            listenerRemovePending = false
        }
    }

    override fun onActive() {
        super.onActive()
        if (listenerRemovePending) {
            Handler(Looper.getMainLooper()).removeCallbacks(removeListener)
        } else {
            query.addValueEventListener(listener)
        }
        listenerRemovePending = false
    }

    override fun onInactive() {
        super.onInactive()
        Handler(Looper.getMainLooper()).postDelayed(removeListener, 2000)
        query.removeEventListener(listener)
    }

    private inner class MyValueEventListener : ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            value = snapshot
        }

        override fun onCancelled(error: DatabaseError) {
            return
        }
    }
}

Activity为了在我的or中读取我的数据库中的值Fragment,这就是我所做的:

val usersViewModel = ViewModelProvider(this).get(UsersViewModel::class.java)
val usersLiveData = usersViewModel.getUsersLiveData()
usersLiveData.observe(this, object : Observer<Users> {
    override fun onChanged(users: Users?) {
        if (users != null) {
            firstNameTextView.text = users.firstName
            lastNameTextView.text = users.lastName
        }
    }
})

这一切都有效,但我的问题是如何在我的Activityor中为我的数据库写一个特定的孩子Fragment?例如,假设我只想修改lastName孩子?我怎么做?FirebaseDatabase我的活动和片段中没有任何引用,因为ViewModelLiveData确保我不再需要它们。

标签: androidkotlinfirebase-realtime-databaseandroid-livedataandroid-viewmodel

解决方案


推荐阅读