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
相关产品推荐
相关产品推荐

