Как установить дочернее значение базы данных Firebase в реальном времени при использовании ViewModel и LiveData?

# #android #kotlin #firebase-realtime-database #android-livedata #android-viewmodel

Вопрос:

У меня есть следующее 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 операционной 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
        }
    }
})
 

Все это работает, но мой вопрос в том, как мне написать конкретному ребенку для моей базы данных в моем Activity или Fragment ? Например, допустим, я хочу изменить только lastName ребенка? Как мне это сделать? У меня нет никаких ссылок FirebaseDatabase на мои действия и фрагменты, потому ViewModel что и LiveData убедитесь, что они мне больше не нужны.

Комментарии:

1. Вы можете перейти lastName от действия к модели просмотра после создания новой функции с логикой обновления базы данных, которая в данном случае является Firebase. Точно так getUsersData же , как вы можете создать новую функцию , скажем setLastName , у вас определенно есть модель DatabaseReference представления, не так ли?

2. И, насколько я знаю, Firebase не будет поддерживать lastName прямое редактирование, вам придется передать Firebase новую User или любую другую вашу модель с обновленным значением свойства, а затем она соответствующим образом обновит ее

3. Что вы до сих пор пробовали в коде для записи данных в базу данных?

4. @AlexMamo Перед использованием a ViewModel и LiveData я бы написал данные следующим образом: Firebase.database.getReference("users").child(auth.currentUser!!.uid).child("lastName").setValue(newValue) . Не уверен, как теперь будет работать запись данных в базу данных без ссылки на базу данных в моих действиях и фрагментах.

5. @gtxtreme Да, у меня DatabaseReference в моем ViewModel , как вы можете видеть, он используется в основном конструкторе.