如何检测用户是否停止写入文本字段?

Pau*_*999 9 android kotlin android-jetpack-compose

我有一个带有 Jetpack Compose 的屏幕,其中有一个 TextField 供用户编写文本。

通过本文,我将进行查询以获取数据。我希望在用户完成输入时进行此查询。

有没有办法知道用户是否需要 2 秒而不写入(例如)来启动此查询?

bko*_*bko 19

另一种方法是完全避免视图模型。利用LaunchedEffect,它会在每次按键(文本)更改时自行取消/重新启动。我发现这比将去抖代码耦合到视图模型要干净得多。

@Composable
private fun TextInput(
    dispatch: (ViewModelEvent) : Unit,
    modifier: Modifier = Modifier
) {

    var someInputText by remember { mutableStateOf(TextFieldValue("")) }

    TextField(
        value = someInputText,
        onValueChange = {
            someInputText = it
        },
    )

    LaunchedEffect(key1 = someInputText) {
        // this check is optional if you want the value to emit from the start
        if (someInputText.text.isBlank()) return@LaunchedEffect

        delay(2000)
        // print or emit to your viewmodel
        dispatch(SomeViewModelEvent(someInputText.text))
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 来自文档:*“如果使用不同的键重新组合 LaunchedEffect(请参阅下面的重新启动效果部分),现有的协程将被取消,新的挂起函数将在新的协程中启动。”* 意味着将调用实际的调度仅当 2 秒过去且未对输入进行进一步更改时 (11认同)

Pha*_*inh 8

要在用户停止输入后 2 秒后进行查询,我认为您可以使用 debounce 运算符(与此处的答案类似的想法Jetpack Compose and Room DB:自动保存用户输入的性能开销?

这是一个处理 上的文本更改的示例TextField,然后查询数据库并将结果返回到dbText

class VM : ViewModel() {
    val text = MutableStateFlow("")
    val dbText = text.debounce(2000)
        .distinctUntilChanged()
        .flatMapLatest {
            queryFromDb(it)
        }

    private fun queryFromDb(query: String): Flow<String> {
        Log.i("TAG", "query from db: " + query)
        if (query.isEmpty()) {
            return flowOf("Empty Result")
        }
        // TODO, do query from DB and return result
    }
}
Run Code Online (Sandbox Code Playgroud)

Composable

Column {
    val text by viewModel.text.collectAsState()
    val dbText by viewModel.dbText.collectAsState("Empty Result")

    TextField(value = text, onValueChange = { viewModel.text.value = it })
    Text(text = dbText)
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案,谢谢。只是不要忘记使用“launchIn(viewModelScope)”或“viewModelScope.launch { }”在视图模型范围内启动它。否则 `.flatMapLatest { queryFromDb(it) }` 不会像我的情况那样触发:) (2认同)