If you are using Kotlin, you can do this with a coroutine. For example, if you want to run the API call 2 seconds after the text has stopped changing it would look like this:
In the Activity or Fragment with a ViewModel
val model: MainViewModel by viewModels()
binding.textInput.doAfterTextChanged { e ->
e?.let { model.registerChange( it.toString() ) }
}
In the ViewModel
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")
}
}
Or without using a 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}")
}
}
}
}
Using Jetpack Compose
The solution using Jetpack Compose is the same, just added to the onValueChange
lambda instead of doAfterTextChanged
(either in place, or the same ViewModel call as before).
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 Solution
If you are using Java, you could use a handler and a postDelayed runnable instead but the flow would be the same (on a text change, cancel the prior task and start a new one with a delay).
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);
}
}
});
}