Android LiveData活动

LiveData是用于将数据和对象的状态与生命周期(LifecycleOwner,通常是片段或活动)链接在一起的好工具。

通常,LiveData放置在ViewModel中,并用于更新UI的状态。 通常,ViewModel可以在LifecycleOwner中存活并保持LiveData状态。 当您需要保存数据并在一段时间后(例如,在配置更改后)将其还原时,这种机制非常适合。

但是,如果我们要使用事件机制而不是状态呢? 并且这在浏览器生命周期的上下文中是必须的(LifecycleOwner)。 例如,我们需要在异步操作之后显示一条消息,前提是LifecycleOwner仍然存在,具有活动的浏览器并且可以更新其UI。 如果我们使用LiveData,则在每次配置更改后或与每个新订户一起收到相同的消息。 建议使用的解决方案之一是在某些浏览器中处理数据之后再处理LiveData中的数据。

例如,如下代码:

Observer { handle(it) yourViewModel.liveData.value = null } 

但是这种方法有几个缺点,不能满足所有必要的要求。

我希望有一个事件机制:

  1. 仅通知活动订户
  2. 订阅时未通知以前的数据,
  3. 可以将已处理标志设置为true,以中断事件的进一步处理。

我实现了MutableLiveEvent类,该类具有上述所有属性,并且可以像正常的LiveData一样工作。

使用方法:

 //   EventArgs        class MyIntEventArgs(data: Int) : EventArgs<Int>(data) //  viewModel class MainViewModel : ViewModel() { private val myEventMutable = MutableLiveEvent<MyIntEventArgs>() val myEvent = myEventMutable as LiveData<MyIntEventArgs> fun sendEvent(data: Int) { myEventMutable.value = MyIntEventArgs(data) } } val vm = ViewModelProviders.of(this).get(MainViewModel::class.java) vm.myEvent.observe(this, Observer { //   /* *   ,    , *      ,   handled = true */ it.handled = true }) 

所有代码都可以在GitHub上获得 ,下面我将讨论一些实现。

 class MutableLiveEvent<T : EventArgs<Any>> : MutableLiveData<T>() { internal val observers = ArraySet<PendingObserver<in T>>() @MainThread override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { val wrapper = PendingObserver(observer) observers.add(wrapper) super.observe(owner, wrapper) } override fun observeForever(observer: Observer<in T>) { val wrapper = PendingObserver(observer) observers.add(wrapper) super.observeForever(observer) } @MainThread override fun removeObserver(observer: Observer<in T>) { when (observer) { is PendingObserver -> { observers.remove(observer) super.removeObserver(observer) } else -> { val pendingObserver = observers.firstOrNull { it.wrappedObserver == observer } if (pendingObserver != null) { observers.remove(pendingObserver) super.removeObserver(pendingObserver) } } } } @MainThread override fun setValue(event: T?) { observers.forEach { it.awaitValue() } super.setValue(event) } } 

这个想法是在MutableLiveEvent类内部,使用obtains和observeForever方法,将浏览器包装在一个特殊的内部类PendingObserver中,该类仅在挂起标志设置为true且尚未处理事件时才调用一次真正的浏览器。

 internal class PendingObserver<T : EventArgs<Any>>(val wrappedObserver: Observer<in T>) : Observer<T> { private var pending = false override fun onChanged(event: T?) { if (pending && event?.handled != true) { pending = false wrappedObserver.onChanged(event) } } fun awaitValue() { pending = true } } 

在PendingObserver中,默认情况下将挂起标志设置为false。 这解决了我们列表中的第2项(不通知旧数据)。

以及MutableLiveEvent中的代码

 override fun setValue(event: T?) { observers.forEach { it.awaitValue() } super.setValue(event) } 

首先将待定设置为true,然后再更新其内部的数据。 这确保了权利要求1的实施。 (仅警告活动的订户)。

我还没有谈到的最后一点是EventArgs。 此类是一种概括,其中存在一个已处理的标志来中断事件的进一步处理(第3节)。

 open class EventArgs<out T>(private val content: T?) { var handled: Boolean = false val data: T? get() { return if (handled) { null } else { content } } } 

就这样,谢谢收看!

Source: https://habr.com/ru/post/zh-CN468749/


All Articles