首页 > 解决方案 > observeForever 生命周期感知吗?

问题描述

我正在使用 MVVM,并且我已经对其进行了不同的实现,但仍然让我怀疑的一件事是如何在不将任何生命周期附加到 ViewModel 的情况下从我的 ViewModel 从存储库 (Firebase) 获取数据。

我已经observeForever()从 ViewModel 实现,但我认为这不是一个好主意,因为我认为我应该使用回调或转换从我的存储库与我的 ViewModel 进行通信。

我在这里留下一个示例,我从 Firebase 获取设备并更新我的 UI,如果我们可以在这里看到,我正在从 UI 观察来自 repo 的数据,但从 ViewModel 我也在观察来自 repo 的数据,在这里我真的怀疑我是否使用了正确的方法,因为我不知道如果我的视图被破坏是否observeForever()会被清除onCleared(),所以如果视图死了它不会让观察者保持活力。

用户界面

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener {
            val deviceId = editText.text.toString().trim()
            observeData(deviceId)
        }
    }

    fun observeData(deviceId:String){
        viewModel.fetchDeviceData(deviceId).observe(this, Observer {
            textView.text = "Tipo: ${it.devType}"
        })

视图模型

class MainViewmodel: ViewModel() {

    private val repo = Repo()
    fun fetchDeviceData(deviceId:String):LiveData<Device>{
        val mutableData = MutableLiveData<Device>()
        repo.getDeviceData(deviceId).observeForever {
            mutableData.value = it
        }

        return mutableData
    }
}

存储库

class Repo {

    private val db = FirebaseDatabase.getInstance().reference
    fun getDeviceData(deviceId:String):LiveData<Device>{
        val mutableData = MutableLiveData<Device>()
        db.child(deviceId).child("config/device").addListenerForSingleValueEvent(object: ValueEventListener{

            override fun onDataChange(dataSnapshot: DataSnapshot) {
                    val device = dataSnapshot.getValue(Device::class.java)
                    mutableData.value = device
            }

            override fun onCancelled(dataError: DatabaseError) {
                Log.e("Error","handle error callback")
            }
        })

        return mutableData
    }
}

这个例子只是展示了如何从 Firebase 中获取设备,它可以工作,但是从我的 ViewModel 中,它一直让我觉得这observeForever()不是我想要在存储库与 ViewModel 之间进行数据通信的东西。

我见过Transformations,但在这种情况下,我只需要将整个 Device 对象传递到我的 UI,因此我不需要将要检索的对象转换为另一个对象

正确的方法来正确地传达存储库和 ViewModel 应该是什么?

标签: androidkotlinmvvmandroid-livedataandroid-architecture-components

解决方案


observeForever 生命周期感知吗?

不,这就是为什么它被称为observeForever

我已经从 ViewModel 实现了 observeForever(),但我认为这不是一个好主意

不,不是,您应该使用Transformations.switchMap {.

因为我不知道如果我的视图被破坏,observeForever() 是否会在 onCleared() 上被清除,所以如果视图死亡,它不会让观察者保持活力。

好吧,如果没有在onCleared()using中清除它removeObserver(observer),那么它不会自行清除,因为它会永远观察。

在这里我真的怀疑我是否使用了正确的方法,

不,您可以按照被动方法做得比这更好。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    button.setOnClickListener {
        val deviceId = editText.text.toString().trim()
        viewModel.onSelectedDeviceChanged(deviceId)
    }

    viewModel.selectedDevice.observe(this, Observer { device ->
        textView.text = "Tipo: ${device.devType}"
    })
}

class MainViewModel(
    private val savedStateHandle: SavedStateHandle,
): ViewModel() {
    private val repo = Repo() // TODO: move to Constructor Argument with ViewModelProvider.Factory

    private val selectedDeviceId: MutableLiveData<String> = savedStateHandle.getLiveData<String>("selectedDeviceId")

    fun onSelectedDeviceChanged(deviceId: String) {
        selectedDeviceId.value = deviceId
    }

    val selectedDevice = Transformations.switchMap(selectedDeviceId) { deviceId ->
        repo.getDeviceData(deviceId)
    }
}

class Repo {
    private val db = FirebaseDatabase.getInstance().reference // TODO: move to constructor arg? Probably

    fun getDeviceData(deviceId:String) : LiveData<Device> {
        return object: MutableLiveData<Device>() {
            private val mutableLiveData = this

            private var query: Query? = null
            private val listener: ValueEventListener = object: ValueEventListener {
                override fun onDataChange(dataSnapshot: DataSnapshot) {
                    val device = dataSnapshot.getValue(Device::class.java)
                    mutableLiveData.value = device
                }

                override fun onCancelled(dataError: DatabaseError) {
                    Log.e("Error","handle error callback")
                }
            }

            override fun onActive() {
                query?.removeEventListener(listener)
                val query = db.child(deviceId).child("config/device")
                this.query = query
                query.addValueEventListener(listener)
            }
    
            override fun onInactive() {
                query?.removeEventListener(listener)
                query = null
            }
        }
    }
}

这样,您可以使用 LiveData 观察 Firebase 中所做的更改(并因此收到对您的值所做的更改的通知),而不是只执行一次提取,然后不知道其他地方对相同数据所做的更改。


推荐阅读