我的当前Android应用程序允许用户远程搜索内容。
例如,用户会看到一个EditText
,接受他们的搜索字符串并触发一个远程API调用,返回与输入文本匹配的结果。
最坏的情况是我只需添加一个TextWatcher
,每次调用onTextChanged
时触发一个API调用。这可以通过强制用户在进行第一次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,但是它们都没有提供所需的解决方案。
是否有可能实现我所需的功能?
动态超时
可接受的解决方案应该应对以下三种情况:
i)用户希望搜索以“P”开头的任何单词
ii)用户希望搜索以“Pneumo”开头的任何单词
iii)用户希望搜索“Pneumonoultramicroscopicsilicovolcanoconiosis”这个词
在所有三种情况下,只要用户键入字母“P”,我就会显示进度旋转器(但此时不会执行任何API调用)。我想平衡在响应式UI中为用户提供搜索反馈的需求与在网络上进行“浪费”的API调用之间的关系。
如果我可以依赖于用户输入其搜索文本,然后单击“完成”(或“Enter”)键,我可以立即启动最终的API调用。
场景一
由于用户输入的文本长度较短(例如,只有1个字符),我的超时值将达到最大值,这为用户提供了输入其他字符的机会,并节省了“浪费的API调用”。
由于用户希望仅搜索字母“P”,因此一旦最大超时时间到期,我将执行API调用并显示结果。这种情况下,用户体验最差,因为他们必须等待我的动态超时到期,然后等待返回和显示大型API响应。他们不会看到任何中间搜索结果。
场景二
如果用户迅速输入所有6个字符,这种情况将结合场景1,我不知道用户要搜索什么(或搜索字符串的最终长度),但是我可以执行一个API调用,但是他们输入6个字符越慢,就越容易执行浪费的API调用。
这种情况给用户提供了更好的用户体验,因为他们必须等待我的动态超时到期,但是他们有机会看到中间搜索结果。与场景1相比,API响应将更小。
场景三
如果用户快速输入所有45个字符,这种情况将结合场景1和2,我不知道用户将要搜索什么(或搜索字符串的最终长度),但是我可以执行一个API调用(也许!),但是他们输入45个字符越慢,就越容易执行浪费的API调用。
我不会被任何可以实现所需解决方案的技术绑定。到目前为止,我认为Rx是最好的方法。