gpt4 book ai didi

android - 如何实现用户输入的周期性处理?

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:43:28 26 4
gpt4 key购买 nike

我当前的 Android 应用程序允许用户远程搜索内容。

例如用户会看到一个 EditText它接受他们的搜索字符串并触发一个远程 API 调用,返回与输入的文本匹配的结果。

更糟糕的情况是我只是添加了一个 TextWatcher并每次触发 API 调用 onTextChanged叫做。这可以通过强制用户在进行第一次 API 调用之前输入至少 N 个字符进行搜索来改进。

“完美”解决方案将具有以下特点:-

一旦用户开始输入搜索字符串

定期(每 M 毫秒)消耗输入的整个字符串。每次周期到期并且当前用户输入与之前的用户输入不同时触发 API 调用。

[是否有可能与输入的文本长度相关的动态超时?例如,当文本“短”时,API 响应大小会很大并且需要更长的时间来返回和解析;随着搜索文本变长,API 响应大小将随着“飞行中”和解析时间而减少]

当用户重新开始在 EditText 字段中输入时,重新开始定期使用文本。

每当用户按下 ENTER 键触发“最终”API 调用,并停止监视用户输入 EditText 字段。

设置用户在触发 API 调用之前必须输入的最小文本长度,但将此最小长度与覆盖超时值相结合,以便当用户希望搜索“短”文本字符串时,他们可以。

我确信 RxJava 和/或 RxBindings 可以支持上述要求,但是到目前为止我还没有实现一个可行的解决方案。

我的尝试包括

private PublishSubject<String> publishSubject;

publishSubject = PublishSubject.create();
publishSubject.filter(text -> text.length() > 2)
.debounce(300, TimeUnit.MILLISECONDS)
.toFlowable(BackpressureStrategy.LATEST)
.subscribe(new Consumer<String>() {
@Override
public void accept(final String s) throws Exception {
Log.d(TAG, "accept() called with: s = [" + s + "]");
}
});


mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {

}

@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
publishSubject.onNext(s.toString());
}

@Override
public void afterTextChanged(final Editable s) {

}
});

这与 RxBinding
 RxTextView.textChanges(mEditText)
.debounce(500, TimeUnit.MILLISECONDS)
.subscribe(new Consumer<CharSequence>(){
@Override
public void accept(final CharSequence charSequence) throws Exception {
Log.d(TAG, "accept() called with: charSequence = [" + charSequence + "]");
}
});

两者都没有给我一个条件过滤器,它结合了输入的文本长度和超时值。

我还用throttleLast 和sample 替换了debounce,两者都没有提供所需的解决方案。

是否有可能实现我所需的功能?

动态超时

一个可接受的解决方案将应对以下三种情况

一)。用户希望搜索以“P”开头的任何单词

ii).用户希望搜索任何以“Pneumo”开头的词

三)。用户希望搜索“Pneumonoultramicroscopicsilicovolcanoconiosis”这个词

在所有三个场景中,只要用户输入字母“P”,我就会显示一个进度微调器(但是此时不会执行 API 调用)。我想在响应式 UI 中为用户提供搜索反馈与通过网络进行“浪费”的 API 调用之间取得平衡。

如果我可以依靠用户输入他们的搜索文本然后单击“完成”(或“回车”)键,我可以立即启动最终的 API 调用。

场景一

由于用户输入的文本长度较短(例如 1 个字符长),我的超时值将处于最大值,这使用户有机会输入其他字符并节省“浪费的 API 调用”。

由于用户希望单独搜索字母“P”,一旦最大超时到期,我将执行 API 调用并显示结果。
这种情况给用户带来了最糟糕的用户体验,因为他们必须等待我的动态超时到期,然后等待返回和显示大型 API 响应。他们不会看到任何中间搜索结果。

场景二

这个场景结合了场景一,因为我不知道用户要搜索什么(或搜索字符串的最终长度),如果他们“快速”输入所有 6 个字符,我可以执行一个 API 调用,但是他们输入 6 的速度越慢字符将增加执行浪费的 API 调用的机会。

这种情况为用户提供了改进的用户体验,因为他们必须等待我的动态超时到期,但他们确实有机会看到中间搜索结果。 API 响应将小于方案一。

场景三

这个场景结合了场景一和场景二,因为我不知道用户要搜索什么(或搜索字符串的最终长度),如果他们“快速”输入所有 45 个字符,我可以执行一个 API 调用(也许!),但是他们键入 45 个字符的速度较慢会增加执行浪费的 API 调用的机会。

我不依赖于提供我想要的解决方案的任何技术。我相信 Rx 是迄今为止我确定的最好的方法。

最佳答案

像这样的东西应该可以工作(并没有真正尝试过)

 Single<String> firstTypeOnlyStream = RxTextView.textChanges(mEditText)
.skipInitialValue()
.map(CharSequence::toString)
.firstOrError();

Observable<CharSequence> restartTypingStream = RxTextView.textChanges(mEditText)
.filter(charSequence -> charSequence.length() == 0);

Single<String> latestTextStream = RxTextView.textChanges(mEditText)
.map(CharSequence::toString)
.firstOrError();

Observable<TextViewEditorActionEvent> enterStream =
RxTextView.editorActionEvents(mEditText, actionEvent -> actionEvent.actionId() == EditorInfo.IME_ACTION_DONE);

firstTypeOnlyStream
.flatMapObservable(__ ->
latestTextStream
.toObservable()
.doOnNext(text -> nextDelay = delayByLength(text.length()))
.repeatWhen(objectObservable -> objectObservable
.flatMap(o -> Observable.timer(nextDelay, TimeUnit.MILLISECONDS)))
.distinctUntilChanged()
.flatMap(text -> {
if (text.length() > MINIMUM_TEXT_LENGTH) {
return apiRequest(text);
} else {
return Observable.empty();
}
})
)
.takeUntil(restartTypingStream)
.repeat()
.takeUntil(enterStream)
.mergeWith(enterStream.flatMap(__ ->
latestTextStream.flatMapObservable(this::apiRequest)
))
.subscribe(requestResult -> {
//do your thing with each request result
});

这个想法是基于采样构建流而不是文本更改事件本身,基于您对每 X 次采样的要求。

我在这里做的方法是构造一个流( firstTypeOnlyStream 用于事件的初始触发(第一次用户输入文本),该流将在用户第一次输入时启动整个处理流,接下来,当第一个触发器到达时,我们基本上将使用 latestTextStream 定期对编辑文本进行采样。 latestTextStream 并不是真正随时间推移的流,而是使用 EditText 属性对 InitialValueObservable 当前状态的采样的 RxBinding(它只是在订阅时发出 EditText 上的当前文本)换句话说,这是一种在订阅时获取当前文本的奇特方式,它相当于:
Observable.fromCallable(() -> mEditText.getText().toString());接下来,对于动态超时/延迟,我们更新 nextDelay基于文本长度并使用 repeatWhen用计时器等待所需的时间。连同 distinctUntilChanged ,它应该根据文本长度给出所需的采样。进一步,我们将根据文本触发请求(如果足够长)。

停止输入 - 使用 takeUntilenterStream这将在 Enter 上触发,它也将触发最终查询。

重启 - 当用户“重新开始”输入时 - 即文本为空, .takeUntil(restartTypingStream) + repeat()将在输入空字符串时停止流,并重新启动它(重新订阅)。

关于android - 如何实现用户输入的周期性处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49277583/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com