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

Android Compose输入TextField时应用崩溃问题求助

Android Compose TextField输入崩溃问题解决

问题描述

开发Android Compose应用时,在TextField中输入字符应用立即崩溃。已通过Profiler检查RAM和CPU无明显异常,排除跳转前foreach语句的问题,但作为新手不会设置断点,无法定位Bug。

代码示例

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            BadmintonTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background
                ) {
                    MyApp(viewModel = MainViewModel())
                }
            }
        }
    }
}
@Composable
fun SinglesLayout(viewModel: MainViewModel) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text("Red")
        TextField(
            value = viewModel.playerNames.getOrNull(0) ?: "",
            onValueChange = {
                viewModel.playerNames[0] = it
            },
            modifier = Modifier.padding(8.dp)
        )
        Text("Blue")
        TextField(
            value = viewModel.playerNames.getOrNull(1) ?: "",
            onValueChange = {
                viewModel.playerNames[1] = it
            },
            modifier = Modifier.padding(8.dp)
        )
    }
}
@Composable
fun MyApp(viewModel: MainViewModel) {
    var isSingles by remember { mutableStateOf(true) }
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "main") {
        composable("main") {
            MainScreen(navController, viewModel)
        }
        composable("next") {
            NextScreen(navController, viewModel)
        }
    }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = { isSingles = !isSingles }) {
            Text(
                text = if (isSingles) {
                    "doubles"
                } else {
                    "singles"
                }
            )
        }
        if (isSingles) {
            SinglesLayout(viewModel = viewModel)
        } else {
            DoublesLayout(viewModel = viewModel)
        }
        Button(onClick = { navController.navigate("next") }) {
            Text("connect")
        }
    }
}
@Composable
fun NextScreen(navController: NavController, viewModel: MainViewModel) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        viewModel.playerNames.forEach() { name ->
            Text(name)
        }
    }
}
@Composable
fun MainScreen(navController: NavController, viewModel: MainViewModel) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = { navController.navigate("next") }) {
        }
    }
}

问题原因

崩溃核心是数组越界异常(IndexOutOfBoundsException):

  • 若MainViewModel中playerNames是普通MutableList且初始为空(如mutableListOf()),输入时onValueChange里直接执行viewModel.playerNames[0] = it,此时列表长度为0,索引0不存在,直接抛出异常导致崩溃。
  • 另外,普通MutableList的修改不会触发Compose重组,即使没有崩溃,UI也无法实时更新输入内容。

修复方案

1. 正确实现MainViewModel

继承ViewModel并使用Compose可观察状态容器管理列表,确保修改能触发重组且避免越界:

import androidx.lifecycle.ViewModel
import androidx.compose.runtime.mutableStateListOf

class MainViewModel : ViewModel() {
    // 初始化填充对应单打模式的空字符串元素
    val playerNames = mutableStateListOf("", "")
}

mutableStateListOf是Compose提供的可观察列表,元素修改会自动触发UI重组。

2. 兼容双打模式的动态调整

如果双打模式需要更多输入框,可在切换模式时调整列表长度:

@Composable
fun MyApp(viewModel: MainViewModel) {
    var isSingles by remember { mutableStateOf(true) }
    val navController = rememberNavController()

    // 切换模式时同步调整列表长度
    LaunchedEffect(isSingles) {
        viewModel.playerNames.apply {
            clear()
            addAll(if (isSingles) listOf("", "") else listOf("", "", "", ""))
        }
    }

    // 剩余代码保持不变...
}

3. 调试断点设置方法

  • 在Android Studio的SinglesLayout中,点击onValueChange代码行(viewModel.playerNames[0] = it)的左侧空白处,设置断点(红色圆点)。
  • 点击工具栏的调试按钮(虫子图标)启动应用,在TextField输入字符时,应用会暂停在断点处,此时可查看viewModel.playerNames的长度和元素,确认是否存在越界问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 13:30:58