观察到Forever生命周期了吗?

时间:2019-11-29 15:15:56

标签: android kotlin mvvm android-livedata android-architecture-components

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

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

我在这里留下一个示例,其中我从Firebase获取设备并更新我的UI,如果可以在此处看到,我正在观察来自UI回购的数据,但是从ViewModel中,我也在观察数据在仓库中,我真的怀疑我是否使用了正确的方法,因为我不知道如果视图被破坏了,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
    }
}

存储库

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中,因此不需要将要检索的对象转换为另一个Object < / p>

在这里,正确地传达存储库和ViewModel的正确方法应该是什么?

3 个答案:

答案 0 :(得分:4)

  

observeForever生命周期知道吗?

不,这就是为什么它被称为observe 永远 的原因。

  

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

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

  

因为我不知道如果我的视图被破坏了,是否会在onCleared()上清除observeForever(),所以如果视图死了,也不会使观察者存活。

如果 您没有使用onCleared()removeObserver(observer)中清除它,则它不会清除自身,因为它观察到< em>永远。

  

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

不,采用被动方法,您可以做得更好。

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

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中的更改(因此会通知您将来对值所做的更改),而不是仅执行一次提取操作,而无需知道在其他位置对同一数据所做的更改

答案 1 :(得分:3)

要使用ObserveForever,您需要删除ViewModel中onClear内部的观察者。

在这种情况下,即使您只需要直接映射而不进行任何数据处理,我还是建议您使用Transformation,这实际上与您对observer.forever的观察器相同。

答案 2 :(得分:1)

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