observeForever 生命周期感知吗?

is observeForever lifecycle aware?

我正在使用 MVVM,我已经对它进行了不同的实现,但仍然让我怀疑的一件事是如何从我的 ViewModel 的存储库 (Firebase) 获取数据而不附加任何生命周期视图模型。

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

我在这里留下一个例子,我从 Firebase 获取设备并更新我的 UI,如果我们能看到这里,我正在观察来自 UI 的 repo 的数据,但是从 ViewModel 我也在观察来自 repo 的数据,在这里我真的怀疑我是否使用了正确的方法,因为我不知道 observeForever() 是否会在 onCleared() 如果我的视图被销毁,那么如果视图死了,它不会让观察者活着。

UI

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,所以我不需要转换我的对象' m 检索到另一个对象

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

要使用ObserveForever,需要移除ViewModel中onClear里面的observer。

在这种情况下,我建议使用转换,即使您只需要直接映射而不对数据进行任何处理,这实际上与您对 observerForever 的观察者所做的相同。

observeForever() 不了解生命周期,将继续 运行 直到 removeObserver() 被调用。 在您的 ViewModel 中执行此操作,

class MainViewmodel: ViewModel() {

    private val repo = Repo()
    private var deviceData : LiveData<Device>? = null
    fun fetchDeviceData(deviceId:String):LiveData<Device>{
        deviceData = repo.getDeviceData(deviceId)
        return deviceData!!
    }
}

is observeForever lifecycle aware?

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

I have implemented observeForever() from the ViewModel, but I don't think that is a good idea

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

since I don't know if observeForever() will be cleared on onCleared() if my view is destroyed, so it won't keep the observer alive if the view dies.

好吧,如果 没有在 onCleared() 中使用 removeObserver(observer) 清除它,那么它就不会' t 清除自身,因为它观察到 forever.

here is where I really doubt if I'm using the right approach,

不,采用被动方法你可以做得比这更好。

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 中所做的更改(因此会收到有关您值的未来更改的通知),而不是只执行一次提取,然后不知道其他地方所做的更改相同的数据。