RxSwift:立即交付第一个项目,消除后续项目

Posted

技术标签:

【中文标题】RxSwift:立即交付第一个项目,消除后续项目【英文标题】:RxSwift: Deliver the first item immediately, debounce following items 【发布时间】:2018-07-15 00:05:30 【问题描述】:

我有一个要验证的文本字段,我想在用户输入时禁用按钮。用户停止输入后(反跳 1 秒),将执行验证并根据结果有条件地启用按钮。请注意当用户只输入一个字符时的极端情况,仍然应该进行验证。

--"a"-"ab"-"abc"------------------"ab"--"a"------------------"ab"-----------------

--false---------validate("abc")---false----validate("a")-----false--validate("ab")

这个 SO (Deliver the first item immediately, 'debounce' following items) 在 RxJava 中提出了以下解决方案。但它似乎只返回第一个元素,而不是当用户在去抖动后再次开始输入时?如果我错了,请纠正我

Observable.from(items).publish(publishedItems -> 
    publishedItems.limit(1).concatWith(
        publishedItems.skip(1).debounce(1, TimeUnit.SECONDS)
    )
)

【问题讨论】:

您是否希望在用户输入时禁用按钮,并在输入完成后与验证功能的结果相匹配? 没错,他们是否完成打字是由debounce决定的 【参考方案1】:

一种选择是将“用户是否在输入”这个问题与“输入是否有效”分开。

描述用户是否在打字的一种(有点笨拙)的方式:

let isTyping = PublishSubject<Bool>()

textField.rx.text
    .map  _ in true 
    .bind(to: isTyping)
    .disposed(by: disposeBag)

textField.rx.text
    .debounce(1.0, scheduler: MainScheduler.instance)
    .map  _ in false
    .bind(to: isTyping)
    .disposed(by: disposeBag)

然后,您可以像这样描述按钮启用状态:

isTyping.withLatestFrom(isValid)  !$0 && $1 
            .bind(to: button.rx.isEnabled)

当然,要让这种方法在用户开始输入时立即生效,最好isValid 以一个值开头。

您还可以通过以下方式简化此过程。如果这些值只在本地使用,这可能没问题。

textField.rx.text
    .map  _ in false 
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

textField.rx.text
    .debounce(1.0, scheduler: MainScheduler.instance)
    .flatMap  [weak self] in self?.validate($0) 
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

请注意,使用这种方法时,需要在用户继续输入时取消异步验证操作。

希望有人可以提出更清洁的解决方案,但我认为这是一个不错的起点。

【讨论】:

其实我也想过第二种方法。一旦用户再次输入,是否有一种反应方式来取消异步操作或忽略其结果? 如果不了解您的应用程序的网络层,我很难回答这个问题。一般来说,重新启动观察的“大锤”选项是重新分配相关的处理包,但我认为这不是你想要的。另一种选择是检查 textField 在验证过程中是否没有更改:【参考方案2】:

经过一番思考,我能够通过以下方式完全解决它,一切都按我的意图进行

    let input = textField.rx.text.distinctUntilChanged()
    let keystroke = input.map  _ in Observable.just(false) 
    let validate = input
        .flatMap  Observable.from(optional: $0)   // 1  
        .filter  $0.count >= minimumTextLength       
        .debounce(1, scheduler: MainScheduler.instance)
        .map  self.networkManager.validate($0).asObservable()  // 2
    return Observable.merge(keystroke, validate).switchLatest().distinctUntilChanged() // 3
    安全地解开可选字符串 validate 在我的例子中返回 Single&lt;Bool&gt;,所以我把它变成 Observable。请注意,我故意使用 map 而不是 flatMap,以便使用步骤 3 中 switchLatest 提供的功能 我合并 a 和 b 以创建 Observable&lt;Observable&lt;Bool&gt;&gt;switchLatest 允许我在用户再次开始输入时忽略 validate 结果。 distinctUntilChanged 丢弃重复的 falses

【讨论】:

以上是关于RxSwift:立即交付第一个项目,消除后续项目的主要内容,如果未能解决你的问题,请参考以下文章

中台之交付

实战交付一套dubbo微服务到k8s集群之使用Jenkins进行持续构建交付dubo服务的提供者

项目交付完毕后,项目经理还要做点什么?

2019春季第三次课程设计实验报告

使用 RxSwift 进行分页 API 调用

(ACP)敏捷项目管理