为什么每个 activity 都在更新原始实时数据而不是最近的实时数据?
Why each activity is getting update to the original live data instead of recent live data?
MeetingViewModel
fun observeAttendeesJoined(): LiveData<Array<AttendeeInfo>>? {
return Repository.getAttendeesJoined()
}
有一个使用 kotlin 的 object 声明的单例存储库。
Repository 有一个正在被 BaseActivity 观察到的实时数据。
存储库
fun getAttendeesJoined(): LiveData<Array<AttendeeInfo>>? {
if (attendeesJoined == null) {
attendeesJoined = MutableLiveData()
}
return attendeesJoined
}
BaseActivity
private fun observeAttendeesJoined() {
meetingViewModel.observeAttendeesJoined()?.observe(this) {
Timber.d(" :$LOG_APP_NAME: BaseActivity: :setObservers: onAttendeesJoined: $it")
lifecycleScope.launchWhenResumed {
onAttendeesJoined(it)
}
}
}
前台服务更改相应可变实时数据的值。
BaseActivity 收到更新,我们正在显示 snackbar。
现在,当我们更改 activity 时,即使不是由前台服务触发,也会再次触发相同的结果。
例如,如果我们在 activity A (that extends the BaseActivity)
并且前台服务将新与会者总数的值更改为 5,我们在 activity A
中将其显示为 5 位用户加入了会议。用户在 activity A
上花费了一些时间。一段时间后,当用户移动到 activity B (that is also extending BaseActivity)
,而前台服务没有任何响应时,activity B
收到与 activity A 收到的相同的最后更新,因此,activity B 还显示 5 位用户已加入会议的快餐栏,并且此模式将持续所有活动。
MeetingViewModel
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)
}
每当前台服务更改相应的可变实时数据时,新 activity(在我们的示例中为 activity B)应该仅在新数据 (5) 发生更改时才进行更新,因为 meetingViewModel.observeAttendeesJoined()
returns 只有新数据。
如何接收跨活动的唯一更新?
MeetingViewModel
的实例对于每个 activity 都是不同的,但是存储库数据是一个单例(object kotlin 声明),不是吗?
我试图理解 Transformations.map
和 switchMap
但不知道如何使用它来解决问题。
谢谢期待
MutableLiveData
存储最后一个值并在您在另一个 Activity
中观察它时发出它(因为您将 MutableLiveData
存储在单例中)。
也许你想要像 SingleLiveEvent
这样的东西。参见 https://medium.com/@abhiappmobiledeveloper/android-singleliveevent-of-livedata-for-ui-event-35d0c58512da
这就是 LiveData 设计的工作方式。它是为了获取最新的数据状态,并不打算成为消息广播者。有各种各样的黑客试图让 LiveData 为这个目的工作。您可以在网络上搜索 SingleLiveEvent 以查找有关该主题的各种文章。
您可以考虑使用 Kotlin 的 MutableSharedFlow 而不是 LiveData 来执行此操作。它有一个 replay
参数,您可以将该参数设置为 0(默认值),这样您的新 Activity 就不会收到已经发生的更新。在我看来,这是比 SingleLiveEvent 更简洁的解决方案。
您的存储库可以公开 属性:
val attendeesJoined = MutableSharedFlow<Array<AttendeeInfo>>()
并且您的 ViewModel 可以通过它:
val attendeesJoined: SharedFlow<Array<AttendeeInfo>> = Repository.getAttendeesJoined()
您可以 post 值到 MutableSharedFlow tryEmit()
。
您的 Activity 可以在其 lifecycleScope
上收集(观察)Flow,这将导致与观察 LiveData 类似的行为,因为 lifeCycleScope
会在 [=32] 时自动取消收集=] 已关闭。
private fun observeAttendeesJoined() {
lifecycleScope.launchWhenResumed {
meetingViewModel.attendeesJoined.collect {
Timber.d(" :$LOG_APP_NAME: BaseActivity: :setObservers: onAttendeesJoined: $it")
onAttendeesJoined(it)
}
}
}
另外,提个建议。应该很少使用数组。存储库公开只读列表是 cleaner/safer。数组是可变的和固定大小的,因此它们的用途很窄,通常用于低级工作。
MeetingViewModel
fun observeAttendeesJoined(): LiveData<Array<AttendeeInfo>>? {
return Repository.getAttendeesJoined()
}
有一个使用 kotlin 的 object 声明的单例存储库。 Repository 有一个正在被 BaseActivity 观察到的实时数据。
存储库
fun getAttendeesJoined(): LiveData<Array<AttendeeInfo>>? {
if (attendeesJoined == null) {
attendeesJoined = MutableLiveData()
}
return attendeesJoined
}
BaseActivity
private fun observeAttendeesJoined() {
meetingViewModel.observeAttendeesJoined()?.observe(this) {
Timber.d(" :$LOG_APP_NAME: BaseActivity: :setObservers: onAttendeesJoined: $it")
lifecycleScope.launchWhenResumed {
onAttendeesJoined(it)
}
}
}
前台服务更改相应可变实时数据的值。 BaseActivity 收到更新,我们正在显示 snackbar。 现在,当我们更改 activity 时,即使不是由前台服务触发,也会再次触发相同的结果。
例如,如果我们在 activity A (that extends the BaseActivity)
并且前台服务将新与会者总数的值更改为 5,我们在 activity A
中将其显示为 5 位用户加入了会议。用户在 activity A
上花费了一些时间。一段时间后,当用户移动到 activity B (that is also extending BaseActivity)
,而前台服务没有任何响应时,activity B
收到与 activity A 收到的相同的最后更新,因此,activity B 还显示 5 位用户已加入会议的快餐栏,并且此模式将持续所有活动。
MeetingViewModel
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)
}
每当前台服务更改相应的可变实时数据时,新 activity(在我们的示例中为 activity B)应该仅在新数据 (5) 发生更改时才进行更新,因为 meetingViewModel.observeAttendeesJoined()
returns 只有新数据。
如何接收跨活动的唯一更新?
MeetingViewModel
的实例对于每个 activity 都是不同的,但是存储库数据是一个单例(object kotlin 声明),不是吗?
我试图理解 Transformations.map
和 switchMap
但不知道如何使用它来解决问题。
谢谢期待
MutableLiveData
存储最后一个值并在您在另一个 Activity
中观察它时发出它(因为您将 MutableLiveData
存储在单例中)。
也许你想要像 SingleLiveEvent
这样的东西。参见 https://medium.com/@abhiappmobiledeveloper/android-singleliveevent-of-livedata-for-ui-event-35d0c58512da
这就是 LiveData 设计的工作方式。它是为了获取最新的数据状态,并不打算成为消息广播者。有各种各样的黑客试图让 LiveData 为这个目的工作。您可以在网络上搜索 SingleLiveEvent 以查找有关该主题的各种文章。
您可以考虑使用 Kotlin 的 MutableSharedFlow 而不是 LiveData 来执行此操作。它有一个 replay
参数,您可以将该参数设置为 0(默认值),这样您的新 Activity 就不会收到已经发生的更新。在我看来,这是比 SingleLiveEvent 更简洁的解决方案。
您的存储库可以公开 属性:
val attendeesJoined = MutableSharedFlow<Array<AttendeeInfo>>()
并且您的 ViewModel 可以通过它:
val attendeesJoined: SharedFlow<Array<AttendeeInfo>> = Repository.getAttendeesJoined()
您可以 post 值到 MutableSharedFlow tryEmit()
。
您的 Activity 可以在其 lifecycleScope
上收集(观察)Flow,这将导致与观察 LiveData 类似的行为,因为 lifeCycleScope
会在 [=32] 时自动取消收集=] 已关闭。
private fun observeAttendeesJoined() {
lifecycleScope.launchWhenResumed {
meetingViewModel.attendeesJoined.collect {
Timber.d(" :$LOG_APP_NAME: BaseActivity: :setObservers: onAttendeesJoined: $it")
onAttendeesJoined(it)
}
}
}
另外,提个建议。应该很少使用数组。存储库公开只读列表是 cleaner/safer。数组是可变的和固定大小的,因此它们的用途很窄,通常用于低级工作。