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

Android Compose中popBackStack返回后Composable重绘致状态丢失问题

解决Jetpack Compose导航返回时状态重置的问题

问题原因

当从SecondScreen返回FirstScreen时,计数器状态重置为0,本质是因为导航离开FirstScreen时,该Composable会被从Composition中移除,使用remember存储的状态会随Composable销毁而丢失;返回时重新创建FirstScreen,状态会重新初始化为0。

解决方案

方案1:状态提升到父Composable

将计数器状态移至NavHost所在的父组件中,父组件不会因导航操作被销毁,状态可持续保留。

修改父组件代码:

@Composable
fun MainScreen() {
    val navController = rememberNavController()
    // 将状态提升到父Composable
    val counter = remember { mutableStateOf(0) }
    
    NavHost(navController = navController, startDestination = "FirstScreen") {
        composable("FirstScreen") {
            FirstScreen(navigation = navController, counter = counter)
        }
        composable("SecondScreen") {
            SecondScreen(navigation = navController)
        }
    }
}

修改FirstScreen接收外部状态:

@Composable
fun FirstScreen(navigation: NavController, counter: MutableState<Int>) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = {
            counter.value = counter.value + 1
        }) {
            Text("Counter : ${counter.value}")
        }
        Button(onClick = {
            navigation.navigate("SecondScreen")
        }) {
            Text("Go to second screen")
        }
    }
}

方案2:使用ViewModel存储状态

ViewModel的生命周期独立于Composable,即使Composable被销毁,ViewModel实例会保留,状态不会丢失。

首先创建ViewModel:

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

class CounterViewModel : ViewModel() {
    private val _counter = MutableStateFlow(0)
    val counter: StateFlow<Int> = _counter.asStateFlow()

    fun incrementCounter() {
        _counter.value += 1
    }
}

在FirstScreen中使用ViewModel:

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun FirstScreen(navigation: NavController) {
    val viewModel: CounterViewModel = viewModel()
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = {
            viewModel.incrementCounter()
        }) {
            Text("Counter : ${viewModel.counter.value}")
        }
        Button(onClick = {
            navigation.navigate("SecondScreen")
        }) {
            Text("Go to second screen")
        }
    }
}

方案3:使用rememberSaveable替代remember

rememberSaveable会将状态保存到Bundle中,即使Composable销毁重建(导航返回、屏幕旋转等场景),状态也能恢复,适合简单可序列化类型。

修改FirstScreen中的计数器状态:

@Composable
fun FirstScreen(navigation: NavController) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // 用rememberSaveable替代remember
        val counter = rememberSaveable { mutableStateOf(0) }
        Button(onClick = {
            counter.value = counter.value + 1
        }) {
            Text("Counter : ${counter.value}")
        }
        Button(onClick = {
            navigation.navigate("SecondScreen")
        }) {
            Text("Go to second screen")
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:43:13