如何在Preview Composable中调用挂起函数?解决调用报错问题
问题解决:Compose预览中调用可组合函数报错
报错原因
你在LaunchedEffect的lambda执行块中调用了PhotosGridScreen这个可组合函数,但LaunchedEffect的lambda属于非可组合上下文,编译器不允许在这种环境下调用带@Composable注解的函数,这就是报错@Composable invocations can only happen from the context of a @Composable function的原因。
正确解决方案
1. 预览场景:直接使用模拟数据
Compose预览的核心是快速查看UI效果,不需要依赖真实的异步数据请求。直接传入模拟的假数据即可:
首先定义模拟数据(根据你的MarsPhoto结构调整):
private val dummyMarsPhotos = listOf( MarsPhoto(id = "test_1", imgSrcUrl = "https://example.com/mars_1.jpg"), MarsPhoto(id = "test_2", imgSrcUrl = "https://example.com/mars_2.jpg") )
然后编写预览函数:
@Preview(showBackground = true) @Composable fun ResultScreenPreview() { MarsPhotosTheme { // 直接传入假数据渲染UI,无需调用真实Repository PhotosGridScreen(photos = dummyMarsPhotos) } }
2. 实际运行场景:用State管理数据+LaunchedEffect请求数据
如果是实际运行的可组合项,需要通过State存储数据,在LaunchedEffect中完成异步请求并更新状态,最后在可组合上下文里根据状态渲染UI:
@Composable fun ResultScreen( marsPhotosRepository: MarsPhotosRepository ) { MarsPhotosTheme { // 用State存储照片数据和加载状态 val photosState = remember { mutableStateOf<List<MarsPhoto>>(emptyList()) } val isLoading = remember { mutableStateOf(true) } // LaunchedEffect仅执行一次,发起异步请求 LaunchedEffect(Unit) { try { val fetchedPhotos = marsPhotosRepository.getMarsPhotos() photosState.value = fetchedPhotos } finally { isLoading.value = false } } // 根据状态渲染不同UI if (isLoading.value) { CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) } else { PhotosGridScreen(photos = photosState.value) } } }
关键要点
- 可组合函数必须在带有
@Composable注解的函数或lambda中调用,LaunchedEffect的执行块不属于这个上下文,只能用来执行异步逻辑,不能直接渲染UI。 - 预览优先使用模拟数据,避免依赖真实的Repository和网络请求,提升预览效率。
内容的提问来源于stack exchange,提问作者NullPointerException
相关产品推荐
相关产品推荐

