问题描述
我正在使用 MVVM,并且已经对其进行了不同的实现,但仍然让我怀疑的一件事是如何从我的 ViewModel 的存储库 (Firebase) 获取数据而不将任何生命周期附加到 ViewModel.
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.
我已经从 ViewModel 中实现了 observeForever()
,但我认为这不是一个好主意,因为我认为我应该通过回调或转换从我的存储库到我的 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.
我在这里留下了一个示例,我从 Firebase 获取设备并更新我的 UI,如果我们在这里可以看到,我正在观察来自 UI 的 repo 的数据,但我也在观察来自 ViewModel 的数据来自 repo,这里是我真正怀疑我是否使用正确方法的地方,因为我不知道 observeForever()
是否会在 onCleared()
上被清除> 如果我的视图被破坏了,那么它不会让观察者在视图死亡时保持活着.
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.
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 之间.
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.
我已经看过Transformations
,但在这种情况下,我只需要将整个设备对象传送到我的 UI,所以我不需要转换我要检索到的对象另一个对象
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
这里应该有什么正确的方法来正确沟通存储库和 ViewModel?
What should be here the right approach to communicate the repository and the ViewModel properly?
推荐答案
不,这就是为什么它被称为observe
Forever.
No, that's why it's called observe
Forever.
我已经从 ViewModel 中实现了 observeForever(),但我认为这不是一个好主意
不,不是,您应该使用 Transformations.switchMap {
.
No, it's not, you should be using Transformations.switchMap {
.
因为我不知道如果我的视图被销毁,observeForever() 是否会在 onCleared() 上被清除,所以如果视图死亡,它不会让观察者保持活动状态.
好吧,如果你没有在 onCleared()
中使用 removeObserver(observer)
清除它,那么它不会自行清除,因为它永远观察.
Well if you're not clearing it in onCleared()
using removeObserver(observer)
, then it won't clear itself, because it observes forever.
这里是我真的怀疑我使用的方法是否正确的地方,
不,您可以通过响应式方法做得比这更好.
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}"
})
}
和
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 中所做的更改(并因此在未来对您的值所做的更改时收到通知),而不是只执行一次提取然后不知道其他地方对相同数据所做的更改.
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.
这篇关于是observeForever 生命周期意识吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!