简体   繁体   English

是observeForever 生命周期意识吗?

[英]is observeForever lifecycle aware?

I'm working with MVVM, and I have made different implementations of it, but one thing that is still making me doubt is how do I get data from a Repository (Firebase) from my ViewModel without attaching any lifecycle to the ViewModel.我正在使用 MVVM,并且已经对其进行了不同的实现,但仍然让我怀疑的一件事是如何从我的 ViewModel 的存储库 (Firebase) 获取数据而不将任何生命周期附加到 ViewModel。

I have implemented observeForever() from the ViewModel, but I don't think that is a good idea because I think I should communicate from my repository to my ViewModel either with a callback or a Transformation.我已经从 ViewModel 实现了observeForever() ,但我认为这不是一个好主意,因为我认为我应该通过回调或转换从我的存储库到我的 ViewModel 进行通信。

I leave here an example where I fetch a device from Firebase and update my UI, if we can see here, I'm observing the data coming from the repo from the UI, but from the ViewModel I'm also observing data from the repo, and here is where I really doubt if I'm using the right approach, 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.我在这里留下一个例子,我从 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}"
        })

ViewModel视图模型

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
    }
}

Repository存储库

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
    }
}

This example just shows how to fetch the device from Firebase, it works, but from my ViewModel, it keeps making me think that observeForever() is not what I'm looking for to communicate data between the repository to the ViewModel.这个例子只是展示了如何从 Firebase 获取设备,它可以工作,但是从我的 ViewModel,它一直让我认为observeForever()不是我想要在存储库和 ViewModel 之间传输数据的东西。

I have seen Transformations , but I, in this case, I just need to deliver the entire Device object to my UI, so I don't need to transform the Object I'm retrieving to another Object我已经看过Transformations ,但在这种情况下,我只需要将整个 Device 对象传送到我的 UI,所以我不需要将我正在检索的对象转换为另一个对象

What should be here the right approach to communicate the repository and the ViewModel properly?正确传达存储库和 ViewModel 的正确方法应该是什么?

is observeForever lifecycle aware?是observeForever 生命周期意识吗?

No, that's why it's called observe Forever .不,这就是为什么它被称为永远observe

I have implemented observeForever() from the ViewModel, but I don't think that is a good idea我已经从 ViewModel 中实现了 observeForever(),但我认为这不是一个好主意

No, it's not, you should be using Transformations.switchMap { .不,不是,您应该使用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.因为我不知道如果我的视图被破坏,observeForever() 是否会在 onCleared() 上被清除,所以如果视图死亡,它不会让观察者保持活动状态。

Well if you're not clearing it in onCleared() using removeObserver(observer) , then it won't clear itself, because it observes forever .好吧,如果没有使用removeObserver(observer)onCleared()清除它,那么它不会自行清除,因为它会永远观察。

here is where I really doubt if I'm using the right approach,这是我真正怀疑我是否使用正确方法的地方,

No, you can do much better than this following a reactive 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}"
    })
}

And

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

    private val selectedDeviceId = MutableLiveData<String>

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

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

And

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
            }
        }
    }
}

This way, you can observe for changes made in Firebase (and therefore be notified of future changes made to your values) using LiveData, rather than only execute a single fetch and then not be aware of changes made elsewhere to the same data.通过这种方式,您可以使用 LiveData 观察 Firebase 中所做的更改(并因此收到对您的值所做的未来更改的通知),而不是只执行一次提取,然后不知道其他地方对相同数据所做的更改。

To use ObserveForever, you need to remove the observer inside onClear in the ViewModel.要使用 ObserveForever,您需要移除 ViewModel 中 onClear 内部的观察者。

In this case, I would suggest to use Transformation even though you just need a direct mapping without any processing of the data, which is actually the same as what you are doing with the observer for observerForever.在这种情况下,我建议使用 Transformation,即使您只需要直接映射而不对数据进行任何处理,这实际上与您使用 ObserverForever 的观察者所做的相同。

observeForever() is not Lifecycle aware and will continue to run until removeObserver() is called. observeForever()不知道生命周期并且会继续运行直到removeObserver()被调用。 In your ViewModel do this instead,在您的 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!!
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM