android - 为什么每个活动都更新到原始实时数据而不是最近的实时数据?
问题描述
会议视图模型
fun observeAttendeesJoined(): LiveData<Array<AttendeeInfo>>? {
return Repository.getAttendeesJoined()
}
有一个使用 kotlin 的对象声明的单例存储库。存储库有一个 BaseActivity 正在观察的实时数据。
存储库
fun getAttendeesJoined(): LiveData<Array<AttendeeInfo>>? {
if (attendeesJoined == null) {
attendeesJoined = MutableLiveData()
}
return attendeesJoined
}
基本活动
private fun observeAttendeesJoined() {
meetingViewModel.observeAttendeesJoined()?.observe(this) {
Timber.d(" :$LOG_APP_NAME: BaseActivity: :setObservers: onAttendeesJoined: $it")
lifecycleScope.launchWhenResumed {
onAttendeesJoined(it)
}
}
}
前台服务会更改相应可变实时数据的值。BaseActivity 收到更新,我们正在显示小吃栏。现在,当我们更改活动时,即使它不是由前台服务触发,也会再次触发相同的结果。
例如,如果我们在activity A (that extends the BaseActivity)
并且前台服务将新参加者总数的值更改为 5,我们将在 5 个用户已加入会议中activity A
显示它。用户在activity A
. 一段时间后,当用户移动到 时activity B (that is also extending BaseActivity)
,前台服务没有任何响应,activity B
接收到的最新更新与活动 A 收到的相同,因此,活动 B 还显示 5 个用户已加入会议的小吃栏,这种模式将持续所有的活动。
会议视图模型
fun onAttendeesJoined(attendeeInfo: Array<AttendeeInfo>) {
Timber.d(" :$LOG_APP_NAME: MeetingViewModel: :onAttendeesJoined: :size: ${attendeeInfo.size}")
attendeeInfo.forEach {
Timber.d(" :$LOG_APP_NAME: MeetingViewModel: :onAttendeesJoined: $attendeeInfo")
}
Repository.setAttendeesJoined(attendeeInfo)
}
服务
override fun onAttendeesJoined(attendeeInfo: Array<AttendeeInfo>) {
attendeeInfo.forEach {
Timber.d(" :$LOG_APP_NAME: ChimeService: :onAttendeesJoined: :id: ${it.attendeeId} :externalId: ${it.externalUserId} :attendeeInfo: $it :responseSize: ${attendeeInfo.size}")
}
meetingViewModel.onAttendeesJoined(attendeeInfo)
}
每当前台服务更改相应的可变实时数据时,新活动(在我们的示例中为活动 B)应仅在新数据 (5) 发生更改时才获得更新,因为meetingViewModel.observeAttendeesJoined()
仅返回新数据。
如何在活动中接收独特的更新?
每个活动的实例MeetingViewModel
都不同,但存储库数据是单例(kotlin 的对象声明),不是吗?
我试图理解Transformations.map
,switchMap
但不知道如何使用它来解决问题。
谢谢你的期待。
解决方案
这就是 LiveData 的工作原理。它是为了获取最新的数据状态,而不是作为消息广播者。有各种黑客可以尝试使 LiveData 用于此目的。您可以对 SingleLiveEvent 进行网络搜索以查找有关该主题的各种文章。
您可以考虑使用 Kotlin 的 MutableSharedFlow 来代替 LiveData。它有一个replay
参数,您可以将其设置为 0(这是默认值),因此您的新活动将不会收到已经发生的更新。在我看来,这是一个比 SingleLiveEvent 更干净的解决方案。
您的 repo 可以公开该属性:
val attendeesJoined = MutableSharedFlow<Array<AttendeeInfo>>()
并且您的 ViewModel 可以通过它:
val attendeesJoined: SharedFlow<Array<AttendeeInfo>> = Repository.getAttendeesJoined()
您可以使用 将值发布到 MutableSharedFlow tryEmit()
。
您的活动可以收集(观察)其lifecycleScope
s 上的流,这将导致类似于观察 LiveData 的行为,因为lifeCycleScope
当活动关闭时将自动取消收集。
private fun observeAttendeesJoined() {
lifecycleScope.launchWhenResumed {
meetingViewModel.attendeesJoined.collect {
Timber.d(" :$LOG_APP_NAME: BaseActivity: :setObservers: onAttendeesJoined: $it")
onAttendeesJoined(it)
}
}
}
另外,提个建议。应该很少使用数组。存储库公开只读列表更清洁/更安全。数组是可变且固定大小的,因此它们的用途很有限,通常用于低级工作。
推荐阅读
- javascript - 无法使用 Builder.load() 动态加载组件
- spring - Spring LdapTemplate org.slf4j.impl.StaticLoggerBinder 问题
- python - 使用 matplotlib 和 pandas 绘制彩色甘特图
- reactjs - 如何使用不可变的方式更新嵌套状态属性
- reactjs - 如何为 React this.setState({}) 的状态变化设置动画?
- java - 将 2 通道的短裤数组写入 WAV 文件
- android - 错误:无法解决:com.klarna.checkout:sdk:1.6.13
- c++ - OpenGL创建基本窗口失败
- mysql - 错误 13540 --- [restartedMain] ohhql.internal.ast.ErrorTracker 意外令牌:DAY
- javascript - NVD3 - 堆积条形图,每隔一个条形后有空格