android - observeForever 生命周期感知吗?
问题描述
我正在使用 MVVM,并且我已经对其进行了不同的实现,但仍然让我怀疑的一件事是如何在不将任何生命周期附加到 ViewModel 的情况下从我的 ViewModel 从存储库 (Firebase) 获取数据。
我已经observeForever()
从 ViewModel 实现,但我认为这不是一个好主意,因为我认为我应该使用回调或转换从我的存储库与我的 ViewModel 进行通信。
我在这里留下一个示例,我从 Firebase 获取设备并更新我的 UI,如果我们可以在这里看到,我正在从 UI 观察来自 repo 的数据,但从 ViewModel 我也在观察来自 repo 的数据,在这里我真的怀疑我是否使用了正确的方法,因为我不知道如果我的视图被破坏是否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,因此我不需要将要检索的对象转换为另一个对象
正确的方法来正确地传达存储库和 ViewModel 应该是什么?
解决方案
observeForever 生命周期感知吗?
不,这就是为什么它被称为observe
Forever。
我已经从 ViewModel 实现了 observeForever(),但我认为这不是一个好主意
不,不是,您应该使用Transformations.switchMap {
.
因为我不知道如果我的视图被破坏,observeForever() 是否会在 onCleared() 上被清除,所以如果视图死亡,它不会让观察者保持活力。
好吧,如果您没有在onCleared()
using中清除它removeObserver(observer)
,那么它不会自行清除,因为它会永远观察。
在这里我真的怀疑我是否使用了正确的方法,
不,您可以按照被动方法做得比这更好。
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 中所做的更改(并因此收到对您的值所做的更改的通知),而不是只执行一次提取,然后不知道其他地方对相同数据所做的更改。
推荐阅读
- javascript - 创建一个函数返回 isFullDay true
- python - 如何使用 2 组用户输入搜索 txt 文件,然后打印相关行?
- asynchronous - Windows IoT:无头(后台)程序中的异步任务创建错误
- android - Android - 匹配三个单独的条件以启用/禁用按钮
- python - 使用带有变量的正则表达式验证条件
- sql - 是否有一个 go 函数来检查从 sql queryContext 返回的行的数量?
- mongoose - NestJS - 如何使用装饰器创建嵌套模式
- javascript - 未捕获的类型错误:无法读取未定义的属性“removeError”
- python - 在 Python 中执行函数后出现“无”(使用 if/elif)
- highcharts - 如果我将最大 y 值设置为 100% 并且我的值高于该值,则不会显示标签