我正在使用MVVM,并且已经对其进行了不同的实现,但是仍然使我感到困惑的一件事是,如何在不将生命周期附加到ViewModel的情况下从ViewModel的Repository(Firebase)获取数据。
我已经从ViewModel实现了observeForever()
,但是我认为这不是一个好主意,因为我认为我应该使用回调或Transformation从存储库向ViewModel进行通信。
我在这里留下一个示例,其中我从Firebase获取设备并更新我的UI,如果可以在此处看到,我正在观察来自UI回购的数据,但是从ViewModel中,我也在观察数据在仓库中,我真的怀疑我是否使用了正确的方法,因为我不知道如果视图被破坏了,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中,因此不需要将要检索的对象转换为另一个Object < / p>
在这里,正确地传达存储库和ViewModel的正确方法应该是什么?
答案 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!!
}
}