如何创建发出单个事件并仅通知最后订阅的观察者的 LiveData? [英] How to create LiveData which emits a single event and notifies only last subscribed observer?

查看:21
本文介绍了如何创建发出单个事件并仅通知最后订阅的观察者的 LiveData?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个实时数据,它发出一个事件,就像在这个 example.

I created live data which emits a single event as in this example.

接下来我的问题是:当 LiveData 中的值发生变化时,如何仅通知最后订阅的观察者?

My question is next: How to notify only last subscribed observer when the value in the LiveData changes?

我想到的是将观察者存储在 SingleLiveData 类的链表中,然后仅当传递的观察者与列表的最后一个元素相同时才调用 super.observe.

What comes to my mind is to store observers in the linked list in SingleLiveData class and then to call super.observe only if a passed observer is the same as the last element of the list.

我不确定这是否是最好的方法.

I'm not sure if this is the best approach.

我想使用这种机制将 FAB 单击事件从活动传播到 ViewPager 中显示的片段.片段是动态添加到视图分页器适配器的,所以假设我们知道片段的顺序.

I want to use this mechanism to propagate FAB click events from activity to the fragments which are shown inside of the ViewPager. Fragments are dynamically added to view pager adapter, so let's say that we know the order of the fragments.

推荐答案

最后,我找到了解决这个问题的方法.我不得不远离发出单个事件的实时数据,因为它无法按照我需要的方式运行.

In the end, I found a workaround for this problem. I had to move away from the live data that emits a single event since it couldn't behave the way I needed it to behave.

取而代之的是,我使用了简单的可变实时数据,它发出一个事件对象,该对象包装数据的最后一段 文章 作者:Jose Alcérreca.

Instead of this, I used simple mutable live data which emits an event object which wraps a data as in the last paragraph of this article by Jose Alcérreca.

我在视图寻呼机中显示片段,所以我当时只有一个可见片段.

I'm showing fragments in a view pager so I have only one visible fragment at the time.

所以我的视图模型是这样的:

So my view model looks like this:

class ActionViewModel : ViewModel() {
  private val onCreateLiveData: MutableLiveData<Event<String>> = MutableLiveData()

  fun observeOnCreateEvent(): LiveData<Event<String>> = onCreateLiveData

  fun onCreateCollectionClick(message: String) {
    this.onCreateLiveData.value = Event(message)
  }
}

事件包装类实现如下所示:

Event wrapper class implementation looks like this:

/*Used as a wrapper for data that is exposed via a LiveData that represents an 
 event.*/

open class Event<out T>(private val content: T) {

  var hasBeenHandled = false
    private set // Allow external read but not write

  /**
   * Returns the content and prevents its use again.
  */
  fun getContentIfNotHandled(): T? {
    return if (hasBeenHandled) {
      null
    } else {
      hasBeenHandled = true
      content
    }
  }

  /**
    * Returns the content, even if it's already been handled.
  */
  fun peekContent(): T = content
}

现在我们可以在片段中观察这样的事件:

In fragments now we can observe events like this:

override fun onActivityCreated(savedInstanceState: Bundle?) {
   super.onActivityCreated(savedInstanceState)

   actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionViewModel::class.java)
   actionViewModel.observeOnCreateEvent()
       .observe(this, Observer {
         it?.takeIf { userVisibleHint }?.getContentIfNotHandled()?.let {
           //DO what ever is needed
         }
       })
}

如果片段当前对用户可见,

Fragment userVisibleHint 属性将返回 true.由于我们当时只显示一个片段,这对我们有用.这意味着片段将仅访问可见的事件数据.

Fragment userVisibleHint property will return true if the fragment is currently visible to the user. Since we are only showing one fragment at the time this works for us. This means that the fragment will only access the event data if it is visible.

此外,事件包装器的实现只允许读取一次值,因此每次 Observer 获取此事件时,其值为 null,我们将忽略它.

Also, implementation of the Event wrapper allows only one read of the value, so that every next time Observer gets this event, its value will be null and we'll ignore it.

结论:通过这种方式,我们模拟了单个事件的实时数据,该数据仅通知最后订阅的观察者.

Conclusion: This way we are simulating a single event live data which notifies only last subscribed observer.

这篇关于如何创建发出单个事件并仅通知最后订阅的观察者的 LiveData?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆