You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose返回导航时保留BasicTextField输入文本方案

问题原因

你当前使用remember存储输入文本,remember存储的状态仅与Composable在Composition视图树中的生命周期绑定。当通过NavHost导航到其他页面时,包含输入框的原Composable会被移出视图树,内部remember保存的状态会被直接回收;返回时Composable重新加入视图树,remember会重新初始化空字符串,最终导致输入内容被清空。

实现方案

方案1:使用rememberSaveable替代remember(快速修复)

rememberSaveable会将状态存入组件所属Activity/Fragment的SavedStateRegistry,只要当前页面还在NavHost的返回栈中,导航离开时状态会被自动持久化,返回时自动恢复,同时还能兼容横竖屏切换、系统低内存回收进程后重启的场景。
仅需修改状态声明的代码即可,修改后的SearchBar代码如下:

@Composable
fun SearchBar(
    modifier: Modifier = Modifier,
    onSearch: (String) -> Unit = {}
) {
    // 仅将remember替换为rememberSaveable
    var text by rememberSaveable {
        mutableStateOf("")
    }

    Box(modifier = modifier) {
        BasicTextField(
            value = text,
            onValueChange = {
                text = it
                onSearch(it)
            },
            maxLines = 1,
            singleLine = true,
            textStyle = TextStyle(color = Color.Black),
            modifier = Modifier
                .fillMaxWidth()
                .shadow(5.dp, CircleShape)
                .background(Color.White, CircleShape)
        )
    }
}

方案2:状态提升(符合Compose最佳实践)

按照Compose单向数据流的设计原则,可组合组件不应该内部持有自身状态,应该将状态向上提升到调用方,由上层统一控制状态的存储和流转,这种方式更适合需要在多个组件间共享输入状态、或者页面逻辑需要主动获取输入内容的场景。
首先改造SearchBar组件,不再内部持有文本状态,改为接收外部传入的状态和回调:

@Composable
fun SearchBar(
    modifier: Modifier = Modifier,
    value: String, // 外部传入的输入文本
    onValueChange: (String) -> Unit, // 文本变化回调
    onSearch: (String) -> Unit = {}
) {
    Box(modifier = modifier) {
        BasicTextField(
            value = value,
            onValueChange = {
                onValueChange(it)
                onSearch(it)
            },
            maxLines = 1,
            singleLine = true,
            textStyle = TextStyle(color = Color.Black),
            modifier = Modifier
                .fillMaxWidth()
                .shadow(5.dp, CircleShape)
                .background(Color.White, CircleShape)
        )
    }
}

之后在调用SearchBar的页面级Composable、或者和页面绑定的ViewModel中存储文本状态即可,只要页面没有被弹出NavHost返回栈,状态就会持续保留。
示例:在页面绑定的ViewModel中存储状态

class SearchViewModel : ViewModel() {
    // 存储搜索输入文本,ViewModel生命周期和页面绑定,页面在返回栈中就不会被销毁
    var searchText by mutableStateOf("")
        private set

    fun onSearchTextChange(newText: String) {
        searchText = newText
    }
}

// 页面中调用
@Composable
fun SearchPage(viewModel: SearchViewModel = viewModel()) {
    SearchBar(
        value = viewModel.searchText,
        onValueChange = viewModel::onSearchTextChange,
        onSearch = { /* 搜索逻辑 */ }
    )
}
注意事项
  • 如果你导航时使用了popUpTo参数将当前页面从返回栈中移除,以上两种方案都无法保留状态,这种场景需要将输入内容存储到跨页面的存储层(比如页面共享的ViewModel、本地缓存等)。
  • 如果输入内容是复杂对象而非基础字符串,需要为rememberSaveable自定义序列化Saver,否则会出现状态序列化失败的问题。

内容的提问来源于stack exchange,提问作者CJR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:06:26