所以我正在尝试构建一个对话框片段屏幕(Android),其中有一个EditText
,用户可以在其中输入所需的用户名。使用RxBindings库的RxTextView.textChanges()
我正在观察EditText
并执行以下操作:
我的存储库的checkUsername()
方法返回Single<Boolean>
以表示用户名是否可用。这是代码:
Observable<String> usernameObservable = RxTextView.textChanges(usernameEditText)
.doOnNext(charSequence -> resetUsernameChecks())
.filter(charSequence -> !TextUtils.isEmpty(charSequence))
.debounce(400, TimeUnit.MILLISECONDS)
.map(CharSequence::toString)
.filter(s -> {
boolean match = s.matches("^(?=.{4,12}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?<![_.])$");
if (!match) showMessage(R.string.profile_dialog_username_hint_invalid, true);
return match;
});
Disposable usernameSubscription = usernameObservable
.subscribe(username -> {
Disposable d = viewModel.checkUsername(username)
.subscribe(available -> {
if (available) {
claimButton.setEnabled(true);
showMessage(R.string.profile_dialog_username_hint_available, false);
} else {
showMessage(R.string.profile_dialog_username_hint_unavailable, true);
}
});
disposables.add(d);
});
disposables.add(usernameSubscription);
使用以下辅助方法:
@UiThread
private void resetUsernameChecks() {
claimButton.setEnabled(false);
usernameInputLayout.setError(null);
}
@UiThread
private void showMessage(@StringRes int message, boolean error) {
showMessage(getString(message), error);
}
@UiThread
private void showMessage(String message, boolean error) {
if (error) {
usernameInputLayout.setErrorTextAppearance(R.style.AppTheme_RedMessage);
} else {
usernameInputLayout.setErrorTextAppearance(R.style.AppTheme_GreenMessage);
}
usernameInputLayout.setError(message);
}
但是,我遇到的问题是 ,以前称为showMessage()
方法中的任何一个都会导致崩溃,因为运行中可能存在后台线程(从而阻止更改UI)或者 checkUsername()
的人会匆匆回来并混淆一切。
基本上,我怎样才能确保我在正确的线程上工作?取消任何延迟的网络呼叫?
修改: 我通过将UI方法封装在Runnable中来修复线程问题。但是,我仍然有取消之前通话的问题。让我们说用户搜索可用的用户名 - nick - 然后快速点击退格。已经解雇的网络呼叫现在返回并且不准确地显示 nic 可用,即使它可能不是。
答案 0 :(得分:0)
因此,要更新UI,您必须在UI Thread中执行此操作。我想,
usernameInputLayout.setErrorTextAppearance(R.style.AppTheme_GreenMessage);
就像UI线程一样,所以你需要使用subscribeOn。
如果您要从日志中显示更多内容,我们就会知道错误。但是,现在,您最好的选择是使用UI线程来更新UI。
usernameObservable.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(v -> //whatever you want )
编辑:我的坏事&#34;默认情况下,Observable在后台线程上运行。&#34;这是错误的。正确的是:它在它定义的线程中运行,除非我们使用subscribeOn()/ observeOn()方法。