【问题标题】:BehaviorSubject isn't considered to be emptyBehaviorSubject 不被认为是空的
【发布时间】:2018-04-20 22:49:27
【问题描述】:

我这样创建BehaviorSubject

private val viewStateSubject: BehaviorSubject<StateT> = BehaviorSubject.create()

稍后我会通过以下方式订阅它:

viewStateDisposable = viewStateSubject
            .defaultIfEmpty(createInitialState())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(view::switchToState)

但它从不发出任何项目。但是,如果我使用默认值创建主题,如下所示:

private val viewStateSubject: BehaviorSubject<StateT> = BehaviorSubject.createDefault(createInitialState())

并从订阅中删除defaultIfEmpty,然后它会发出默认值。 AFAIK 这是因为默认情况下 BehaviorSubject 是用 EMPTY 值初始化的,所以它实际上永远不会为空。

很遗憾,我无法使用第二种解决方案。那我怎样才能切换到默认值呢?请注意,我希望能够多次订阅和取消订阅同一主题,并且仅在第一次订阅时接收默认值。这意味着我不能立即将默认值传递给主题或skip

【问题讨论】:

  • defaultIfEmpty 要求源在没有项目的情况下完成。为什么不能使用第二种解决方案?您可以使用 startWith 或简单地将初始值推送到 BehaviorSubject 中。
  • 如您所见,初始值是通过方法提供的。它不是最终方法,我在构造函数中启动主题。我是使用 startWith 还是 push 那么这个值将在每次尝试订阅时被推送,而我只在第一个时才需要它。
  • 所以你有多个消费者,你希望他们中只有一个收到初始值?
  • 没有。我需要一个项目,除非我发布新项目,否则它将为任何人发布。同时我不能使用createDefault。
  • 你可以访问viewStateSubject吗?如果是,请尽早致电viewStateSubject.onNext(initialObject)。也不知道为什么你不能拥有createDefault,但这是更合适的方式。谁拥有该创建代码?

标签: java kotlin rx-java rx-java2


【解决方案1】:

AFAIK 这是因为默认情况下 BehaviorSubject 是用 EMPTY 值初始化的,所以它实际上永远不会为空。

不,BehaviorSubject 在没有默认项的情况下创建时不会发出任何内容。这就是为什么它在你的情况下永远不会发出任何东西。


关于defaultIfEmpty()

defaultIfEmpty() 仅在Observable 完成且不发出任何项目时才会生效。因此,只有在完成发射项目后,您才可以在 viewStateSubject 上调用 onCompleted()


请注意,我希望能够多次订阅和取消订阅同一主题,并且仅在第一次订阅时接收默认值。

我认为BehaviorSubject.create() 和默认项目或defaultIfEmpty() 都不能为您服务。

BehaviorSubject.create() 带有默认项: 这将始终发出该默认值,无论它是否是第一次订阅,只要没有明确发出的项目。

defaultIfEmpty():如前所述,这只有在 BehaviorSubject 完成且未发出任何项目时才会生效。


编辑:在 cmets 中澄清后:

您可以简单地先发出您的默认项目。除非发出任何其他项目,否则每个新订阅者都会收到该项目。

来自doc

向每个订阅的 Observer 发出最近观察到的项目和所有后续观察到的项目的主题。

viewStateSubject.onNext(createInitialState());
viewStateDisposable = viewStateSubject
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(view::switchToState)

【讨论】:

  • 可能我的需求描述错了。我需要一个项目,它将按主题为任何消费者发布,直到我发布另一个项目。因此,createDefault 的作用正是如此,但没有使用 createDefault。
  • 我需要万能订阅码,可以多次调用。在更新答案的示例中,如果我第一次运行此代码,那么结果是可以预期的。但是,如果我随后将新项目发送到主题并为另一个订阅者运行相同的代码 - 它将获得默认项目而不是最后一个发出的项目。
  • @Lingviston 您应该只在开始时调用一次viewStateSubject.onNext(createInitialState())
  • 这很清楚。有什么办法以反应的方式做到这一点?不添加标志或类似的东西。
  • 反应方式是BehaviorSubject.createDefault()。除此之外,我不确定是否有办法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-06
  • 2019-12-05
  • 1970-01-01
  • 1970-01-01
  • 2016-10-21
  • 1970-01-01
相关资源
最近更新 更多