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

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

问题描述

我创建了实时数据,该数据会发出单个事件,如

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.

相反,我使用了简单的可变实时数据,该数据会发出一个事件对象,该事件对象将数据包装在一起,如本

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
         }
       })
}

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

片段 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天全站免登陆