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

Jetpack Compose可组合函数中为何需要添加remember关键字?

问题描述

代码A来自ThemingCodelab项目,我认为代码A中的remember关键字并非必要。我测试了代码B,运行结果看起来和代码A完全一致。请问为什么作者要在这个@Composable中添加remember关键字?

代码A

@Composable
fun Home() {
    val featured = remember { PostRepo.getFeaturedPost() }
    val posts = remember { PostRepo.getPosts() }
    MaterialTheme {
        Scaffold(
            topBar = { AppBar() }
        ) { innerPadding ->
            LazyColumn(contentPadding = innerPadding) {
                item {
                    Header(stringResource(R.string.top))
                }
                item {
                    FeaturedPost(
                        post = featured,
                        modifier = Modifier.padding(16.dp)
                    )
                }
                item {
                    Header(stringResource(R.string.popular))
                }
                items(posts) { post ->
                    PostItem(post = post)
                    Divider(startIndent = 72.dp)
                }
            }
        }
    }
}

代码B

@Composable
fun Home() {
    val featured = PostRepo.getFeaturedPost() 
    val posts = PostRepo.getPosts() 
    //其余代码与上述代码一致
}

解答

你测试时没看出两段代码的差异,只是没有触发会暴露问题的场景而已,加remember是符合Compose开发规范的必要写法,核心原因有两个:

  • 避免重组时重复执行数据拉取逻辑
    Composable会在很多场景下触发重组,比如系统主题切换、屏幕旋转、页面内其他状态更新引发的整体重组。如果不加remember,每次重组都会重新执行PostRepo.getFeaturedPost()和PostRepo.getPosts()这两个数据查询逻辑,哪怕数据没有变化也会重复运行,平白消耗性能。
    加了remember之后,只要Home组件没有被销毁(比如没有从返回栈中移除),这两个方法的返回值就会被缓存,重组时直接复用缓存结果,不需要重复查询。
  • 避免页面意外刷新
    如果PostRepo的这两个方法每次调用返回的是不同的对象实例,哪怕实例的内容完全一致,没有被remember缓存的话,每次重组都会给featured和posts赋值新实例,会触发下游的FeaturedPost、LazyColumn等组件不必要的重绘,极端情况下甚至会出现列表滚动位置丢失、跳回顶部的问题。

你测试时没发现问题,大概率是因为测试场景太简单,没有触发Home组件的重组,或者PostRepo的这两个方法返回的是全局静态的同一个对象,所以看不出差异,但这种写法是不符合Compose最佳实践的,后续需求迭代、逻辑变复杂之后很容易出隐藏问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:06:03