Android Questions: Spot Bugs
Published in Android开发问答, 2025
When this code is run, the Column doesn’t render the background color that was applied to it. Why is that?
@Composable
fun MainScreen(
modifier: Modifier = Modifier,
nightModeEnabled: Boolean = false
) {
val screenModifier = modifier
.background(color = AppColors.background)
.fillMaxSize()
AppTheme(darkMode = nightModeEnabled) {
Column(modifier = screenModifier) {
// Your content here
}
}
}
Answer: 主题覆盖了背景:AppTheme 可能已经为其内容设置了背景色,这会覆盖你在 Column 上设置的背景色
Solution:
@Composable
fun MainScreen(
modifier: Modifier = Modifier,
nightModeEnabled: Boolean = false
) {
AppTheme(darkMode = nightModeEnabled) {
Column(
modifier = modifier
// Here, the background color is accessed
// only in the scope of the AppTheme
.background(color = AppColors.background)
.fillMaxSize()
) {
// Your content here
}
}
}
When an item in the list is clicked, our users keep tripping a ConcurrentModificationException. Can you see why the bug that makes the app crash?
@Composable
fun SmoothScrollingList(
items: List<String>,
onItemClick: (String) -> Unit
) {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
LazyColumn(state = listState) {
items(items) { item ->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.clickable {
onItemClick(item)
scope.launch {
listState.animateScrollToItem(0)
}
}
) {
Text(item, Modifier.padding(16.dp))
}
}
}
}
How do we fix it? Re-order the operations— Scroll first (while the list is still intact), then mutate.
@Composable fun SmoothScrollingList( items: List<String>, onItemClick: (String) -> Unit ) { val listState = rememberLazyListState() val scope = rememberCoroutineScope()
LazyColumn(state = listState) {
items(
items = items,
key = { it } // stable keys help recycling
) { item ->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.clickable {
scope.launch {
// ⬅️ scroll first mutate afterwards
listState.animateScrollToItem(0)
onItemClick(item)
}
}
) {
Text(item, Modifier.padding(16.dp))
}
}
}
When this code runs, scrolling the list causes items to lose their expanded state unexpectedly. Why does this happen?
@Composable
fun ItemsList(items: List<String>) {
LazyColumn {
itemsIndexed(items) { index, item ->
var isExpanded by remember { mutableStateOf(false) }
Card(
modifier = Modifier
.fillMaxWidth()
.clickable { isExpanded = !isExpanded }
) {
Column {
Text(text = item)
if (isExpanded) {
Text(
text = "Extended for $item",
)
}
}
}
}
}
}
Answer: The issue is that remember without a key doesn’t survive item recomposition during scrolling. LazyColumn recycles composables, so the isExpanded state gets reset when items scroll in and out of view.
Fix it by providing a stable key:
var isExpanded by remember(item) { mutableStateOf(false) }
// or better yet, manage state outside the composable

发表评论