📜  如何在 Android 中使用 SingleLiveEvent 仅观察一次事件?

📅  最后修改于: 2022-05-13 01:54:34.502000             🧑  作者: Mango

如何在 Android 中使用 SingleLiveEvent 仅观察一次事件?

您是否曾经处理过 Dialog 或 SnackBar,它们在被触发/显示或关闭后,在设备旋转后再次被触发/显示?这很可能与使用 LiveData observables 在 ViewModel 和 Activity/Fragment 之间进行通信有关。

模式的相反

将 LiveData 对象用于事件可能被视为一种糟糕的设计选择,尤其是当事件只需要一次时。我们可以使用一些布尔标志来帮助视图确定是否应该触发/显示 Dialog/SnackBar。但是,这可能会导致解决方案难以理解和维护,并且没有吸引力。可以看到它是live data的类型,数据是连续消费的,但是我们只想获取一次

没有内存泄漏:

观察者与 Lifecycle 对象相关联,并在它们所连接的生命周期被破坏时自行清理。

没有因活动停止而导致的事故:



如果观察者的生命周期是空闲的,就像在返回堆栈活动的情况下一样,它不会收到任何 LiveData 事件。 LiveData 只是遵循观察者的设计,我不相信上述用例保证它自己的可观察类变体。那么,如何解决对话问题呢?我们不应该改变 LiveData 的行为,而是应该遵循 MVVM 范式的基础知识,并在必要时让 ViewModel 告诉 ViewModel 有关被解除对话的信息。之后,VM 可能会重置或更改事件的状态。我意识到忘记提醒 ViewModel 很容易,我们正在增加 View 的职责。但是,归根结底,这是视图的工作:将任何用户操作通知 VM。

如何实现这一目标?

创建一个通用的“事件”类(可能称之为 LiveEvent)。给它observe(owner,observer) 和observeForever 函数(observer)。赋予它与 LiveData 相同的契约和功能。除此之外,LiveEvent 只是在发送数据时通知活动观察者,而不是持久值。

Kotlin
class LiveEvent {
...
  fun sendingValue(data: C) {
    observers.forEach { gfg ->
      if (gfg.isActive()) gfg.onChanged(data)
    }
  }
}


Kotlin
abstract class GeeksforGeeksViewModel : ViewModel() {
  protected val fireAlertedEvent = LiveEvent()
}
abstract class BaseFragment : Fragment() {
  fun onViewModelInitialized() {
    viewModel.fireAlertedEvent.observe(this, { fireAlert ->
      fireAlert.show()
    }
  }
}
class GeeksforGeeksSample : GeeksforGeeksViewModel() {
  fun onSaveSuccess() {
    fireAlertedEvent.postValue(FireAlert("yay! we got your stuff!"))
  }
}


如果您想将 LiveEvent 用于在多个屏幕上发布通知、SnackBar 或任何内容,请将它放在您的基本 ViewModel 类中。然后,在您的基本 Fragment 类中初始化 ViewModel 之后,注意该 LiveEvent。

科特林

abstract class GeeksforGeeksViewModel : ViewModel() {
  protected val fireAlertedEvent = LiveEvent()
}
abstract class BaseFragment : Fragment() {
  fun onViewModelInitialized() {
    viewModel.fireAlertedEvent.observe(this, { fireAlert ->
      fireAlert.show()
    }
  }
}
class GeeksforGeeksSample : GeeksforGeeksViewModel() {
  fun onSaveSuccess() {
    fireAlertedEvent.postValue(FireAlert("yay! we got your stuff!"))
  }
}

结论

最佳解决方案是在销毁时自动取消订阅的事件源,只要没有观察者存在,就会将事件排入队列,然后将所有事件发送给第一个订阅的观察者。它可以以它认为合适的任何方式处理事件。当您需要管理流程时,使用具有不同成功/失败方法的回调是一个糟糕的主意。使用 ADT(密封类)。

想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!