我使用带有 TextWatcher 的 EditText 文本字段。所有回调方法都会在我输入的每个字符上触发事件。就我而言,我在更改的文本上调用 api,将响应放入同一 fragment 的标签中。我无法检查 EditText 的某种格式,因为它将是自由文本。
示例: 你叫什么名字?
E -> api call
R -> api call
I _> api call
K -> api call
如何避免这种情况?我可以使用计时器(例如 2 秒内没有文本更改 -> api 调用)吗?也许有一种优雅的方法可以做到这一点。
最佳答案
如果您使用 Kotlin,则可以使用协程来完成此操作。例如,如果您想在文本停止更改后 2 秒运行 API 调用,则如下所示:
在具有 ViewModel 的 Activity 或 Fragment 中
val model: MainViewModel by viewModels()
binding.textInput.doAfterTextChanged { e ->
e?.let { model.registerChange( it.toString() ) }
}
在 View 模型中
private var job: Job? = null
fun registerChange(s: String) {
job?.cancel() // cancel prior job on a new change in text
job = viewModelScope.launch {
delay(2_000)
println("Do API call with $s")
}
}
或者不使用 ViewModel
private var job: Job? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.textInput.doAfterTextChanged { e ->
e?.let {
job?.cancel()
job = lifecycleScope.launch {
delay(1_000)
println("Do API call with ${it}")
}
}
}
}
使用 Jetpack Compose
使用 Jetpack Compose 的解决方案是相同的,只是添加到 onValueChange
lambda 而不是 doAfterTextChanged
(就地或与之前相同的 ViewModel 调用)。
private var job: Job? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val textState = remember { mutableStateOf("") }
TextField(
value = textState.value,
onValueChange = {
textState.value = it
job?.cancel()
job = lifecycleScope.launch {
delay(2_000)
println("TEST: Do API call with $it")
}
}
)
}
}
Java 解决方案
如果您使用 Java,则可以使用处理程序和 postDelayed runnable,但流程是相同的(在文本更改时,取消先前的任务并延迟启动一个新任务)。
private final Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText textInput = findViewById(R.id.text_input);
textInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
if( s != null ) {
handler.removeCallbacksAndMessages(null);
handler.postDelayed(() -> {
System.out.println("Call API with " + s.toString());
}, 2000);
}
}
});
}
关于android - 避免 EditText TextWatcher 在每次字符更改时触发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70632237/