小米Compose专项面经:Compose性能优化、Compose自定义Layout怎么实现、Compose动画的核心API

30 阅读4分钟

小米Compose专项面试:小米Android开发覆盖MIUI系统定制、IoT设备互联。技术栈偏底层,面试官喜欢问系统级原理和性能数据。技术方向偏向MIUI定制、IoT互联。特色专项包括MIUI系统定制与IoT设备开发。今天8道题覆盖小米Compose专项面试核心考点。

Q1:Compose性能优化:稳定性(stability)和跳过(skippable)?

Compose性能核心是减少不必要的重组。1)稳定类型(Stable)——所有字段不可变(val+稳定类型),Compose可以安全跳过重组。不稳定的类型(如List/Map)每次都触发重组;2)@Stable/@Immutable注解——手动标记类型为稳定;3)remember derivedStateOf——只有派生结果变化才重组;4)避免lambda分配——用remember包裹lambda或定义在Composable外部。compose compiler report可以分析哪些Composable是skippable的。

// 不稳定——List每次都重组
data class UiState(val items: List<Item>) // List不稳定
// 稳定——用ImmutableList
@Immutable
data class UiState(val items: ImmutableList<Item>)
// 或用@Stable标记
@Stable
data class UiState(val items: List<Item>)

追问:怎么检查Composable是否可跳过?composeCompilerReports生成报告,skipscolumn显示true/false。不可跳出的原因是参数类型不稳定。

Q2:Compose自定义Layout怎么实现?

用Layout composable代替Box/Column/Row实现自定义布局。核心:measurables(子元素列表)→测量每个子元素→确定总体大小→place放置子元素。本质跟View体系的onMeasure+onLayout一样,只是用了声明式API。

@Composable
fun StaggeredGrid(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
    Layout(content = content, modifier = modifier) { measurables, constraints ->
        val placeables = measurables.map { it.measure(constraints) }
        layout(constraints.maxWidth, constraints.maxHeight) {
            var y = 0
            placeables.forEach { p -> p.placeRelative(x = 0, y = y); y += p.height }
        }
    }
}

追问:自定义Layout时intrinsic测量什么时候用?需要根据子元素的内在尺寸来计算自身尺寸时用——如Text的宽度按内容计算。

Q3:Compose动画的核心API?

animateXxxAsState——最简单的单值动画(animateColorAsState, animateDpAsState等);Animatable——更精细控制的动画(支持spring/tween等);Transition——多属性同步动画(如状态切换时多个属性一起动);AnimatedVisibility——显示/隐藏动画(expand/shrink/fade/slide)。底层都基于协程和差值器。

val isExpanded by remember { mutableStateOf(false) }
val rotation by animateFloatAsState(
    targetValue = if (isExpanded) 180f else 0f,
    animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy)
)
Icon(modifier = Modifier.rotate(rotation), ...)

追问:Compose动画和View动画的区别?Compose动画基于State驱动+协程,声明式且与重组自然集成;View动画基于属性+时间。

Q4:Compose主题和Material3适配?

MaterialTheme提供Color/Typography/Shapes三套设计令牌。ColorScheme定义主题色——Material3支持Dynamic Color(Monet, 从壁纸提取调色板)。Typography定义文字层级(display/headline/title/body/label)。Shapes定义组件形状(圆角等)。在@Composable中通过MaterialTheme.colors/typography/shapes自动获取当前主题值。

@Composable
fun MyAppTheme(darkTheme: Boolean, content: @Composable () -> Unit) {
    val colorScheme = if (darkTheme) darkColorScheme(
        primary = Purple80, secondary = PurpleGrey80
    ) else lightColorScheme(
        primary = Purple40, secondary = PurpleGrey40
    )
    MaterialTheme(colorScheme = colorScheme, typography = Typography, content = content)
}

追问:Dynamic Color的兼容性?Android 12+原生支持,低版本需要用androidx.compose.material3:material3兼容库。

Q5:Compose测试和UI预览?

Compose测试用createComposeRule——在JVM上运行Composable并断言UI状态。核心API:onNodeWithText/onNodeWithTag查找节点,performClick/performTextInput模拟交互,assertExists/assertTextEquals断言。Preview是@Preview注解——编译时在IDE中渲染Composable预览,支持多设备/深色模式/字体大小预览。@PreviewLightDark/@PreviewFontScale自动生成多种配置预览。

@Composable
fun Greeting(name: String) { Text("Hello, $name!") }
@Preview(showBackground = true)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun GreetingPreview() { Greeting("Android") }

追问:怎么测试有ViewModel的Composable?用createComposeRule + hiltViewModel需要Hilt测试环境,或直接传入mock ViewModel。

Q6:Compose的副作用(effect)API?

Compose函数应该纯函数无副作用,副作用用Effect API管理:LaunchedEffect(key)——key变化时在协程中执行(如首次加载数据);DisposableEffect(key)——需要清理的副作用(如注册/注销监听器);SideEffect——每次重组后执行(将Compose状态同步到非Compose代码);rememberCoroutineScope——获取Composable绑定的协程作用域。

下一篇进入小米算法高频题——快速排序原理、两数之和(哈希表一次遍历)、有效的括号(栈的应用)。

觉得有用的同学扣1,你面试被追问最狠的是哪道题?

本系列连载中,关注不迷路,下一篇:小米算法高频题面经:快速排序原理、两数之和(哈希表一次遍历)、有效的括号(栈的应用)

系列简介:Android大厂面经连载,覆盖字节跳动、腾讯、阿里、美团等40+企业,从初级到架构师全岗位覆盖。每篇文章包含真实面试题+详细答案+代码示例,帮你拿到大厂Offer。