gpt4 book ai didi

android - 让每个观察者在订阅/观察时只接收 *new* LiveData

转载 作者:行者123 更新时间:2023-12-04 11:36:51 25 4
gpt4 key购买 nike

无论何时调用 .observe()在 LiveData 上,观察者接收该 LiveData 的最后一个值。这在某些情况下可能有用,但在我的情况下没有用。

  • 每当我调用 .observe() ,我希望观察者只接收 future 的 LiveData 更改,而不是它在 .observe() 时所持有的值叫做。
  • 对于 LiveData 实例,我可能有多个观察者。我希望他们都在发生 LiveData 更新时收到它们。
  • 我希望每个观察者只使用一次 LiveData 更新。 我认为这只是对第一个要求的重新表述,但我的头脑已经在旋转,我不确定。


  • 在谷歌搜索这个问题时,我遇到了两种常见的方法:
  • 将数据包装在 LiveData<SingleEvent<Data>> 中并 checkin 此SingleEvent如果它已经被消耗掉了。
  • 扩展 MediatorLiveData如果观察者已经收到事件
  • ,则使用查找图

    可以在此处找到这些方法的示例:
    https://gist.github.com/JoseAlcerreca/5b661f1800e1e654f07cc54fe87441af#gistcomment-2783677
    https://gist.github.com/hadilq/f095120348a6a14251a02aca329f1845#file-liveevent-kt
    https://gist.github.com/JoseAlcerreca/5b661f1800e1e654f07cc54fe87441af#file-event-kt

    不幸的是,这些例子都不能解决我的所有要求。大多数时候,问题是任何新的观察者在订阅时仍然会收到最后一个 LiveData 值。这意味着每当用户在屏幕之间导航时,已经显示的 Snackbar 会一次又一次地显示。

    为了让您了解我在说什么/我在编码什么:

    我正在关注 Android Architecture Componentns 的 LiveData MVVM 设计:
  • 2 ListFragment 显示条目列表。
  • 他们使用同一个 ViewModel 类的 2 个实例来观察与 UI 相关的 LiveData。
  • 用户可以删除此类 ListFragment 中的条目。删除由 ViewModel 调用 Repository.delete() 完成。
  • ViewModel 观察 RepositoryEvents 的存储库.

  • 因此,当删除完成时,Repository 会通知 ViewModel,ViewModel 会通知 ListFragment。

    现在,当用户切换到第二个 ListFragment 时,会发生以下情况:
  • 第二个 Fragment 被创建并调用 .observe()在其 ViewModel
  • ViewModel 被创建并调用 .observe()在存储库
  • 存储库发送其当前 RepositoryEvent到 ViewModel
  • ViewModel 将相应的 UI 事件发送到 Fragment
  • Fragment 显示了一个确认 Snackbar,用于在其他地方发生的删除。

  • 下面是一些简化的代码:

    fragment :
    viewModel.dataEvents.observe(viewLifecycleOwner, Observer { showSnackbar() })
    viewModel.deleteEntry()

    查看型号:
    val dataEvents: LiveData<EntryListEvent> = Transformations.switchMap(repository.events, ::handleRepoEvent)
    fun deleteEntry() = repository.deleteEntry()
    private fun handleRepoEvent(event: RepositoryEvent): LiveData<EntryListEvent> {
    // convert the repository event to an UI event
    }

    存储库:
    private val _events = MutableLiveData<RepositoryEvent>()
    val events: LiveData<RepositoryEvent>
    get() = _events

    fun deleteEntry() {
    // delete it from database
    _events.postValue(RepositoryEvent.OnDeleteSuccess)
    }

    最佳答案

    2021 年更新:
    使用协程库和 Flow 现在很容易通过实现 Channels 来实现。 :
    主要 Activity

    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import androidx.lifecycle.ViewModelProvider
    import androidx.lifecycle.lifecycleScope
    import com.google.android.material.snackbar.Snackbar
    import com.plcoding.kotlinchannels.databinding.ActivityMainBinding
    import kotlinx.coroutines.flow.collect

    class MainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
    viewModel = ViewModelProvider(this).get(MainViewModel::class.java)

    binding.btnShowSnackbar.setOnClickListener {
    viewModel.triggerEvent()
    }

    lifecycleScope.launchWhenStarted {
    viewModel.eventFlow.collect { event ->
    when(event) {
    is MainViewModel.MyEvent.ErrorEvent -> {
    Snackbar.make(binding.root, event.message, Snackbar.LENGTH_LONG).show()
    }
    }
    }
    }

    }
    }
    主视图型号
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.viewModelScope
    import kotlinx.coroutines.channels.Channel
    import kotlinx.coroutines.channels.consumeEach
    import kotlinx.coroutines.flow.receiveAsFlow
    import kotlinx.coroutines.launch

    class MainViewModel : ViewModel() {

    sealed class MyEvent {
    data class ErrorEvent(val message: String): MyEvent()
    }

    private val eventChannel = Channel<MyEvent>()
    val eventFlow = eventChannel.receiveAsFlow()

    fun triggerEvent() = viewModelScope.launch {
    eventChannel.send(MyEvent.ErrorEvent("This is an error"))
    }
    }

    关于android - 让每个观察者在订阅/观察时只接收 *new* LiveData,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55883370/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com