为什么我的代码会导致 jetpack compose 中不必要的重组?

问题描述 投票:0回答:2

我编写了一些显示图像和视频的代码。我正在使用 viewModel,但在下面的代码中,即使数据没有变化,可组合性也会进行不必要的重组。它还会导致其子可组合项的重组时间与

MediaScreenBody()
的计数相同甚至更多。我尝试了很多方法,例如将 by 与collectAsState一起使用,但这些方法甚至导致了 10 倍的重组。第一次启动应用程序时,每个可组合项只有一个组合。然后如果我与应用程序交互,例如滑动或滚动,然后它也会重新组合
MediaSceenBpody()
及其子内容。由于重组,它还会导致滚动和滑动的滞后行为。我做了一些研究,发现 pagerState 可能会导致此问题。我尝试将 pagerState 设置为不同的数字,并且重组也更改为该数字。但请记住,有时它会导致更多的问题。那里没有必要只重组 pageState 的数量。我分享这个仅供大家参考。
MediaSceenBpody()

编辑-

因为有很多关于不将状态或 viemodel 作为参数传递的建议。我尝试在使用 HorizontalPager 的 @Composable fun MediaScreen(onMediaItemClick: () -> Unit) { val mediaViewModel: MediaViewModel = viewModel( factory = MediaViewModel.Factory ) val photoUIState = mediaViewModel.photoUIState.collectAsState() val videoUIState = mediaViewModel.videoUIState.collectAsState() ScreenContent( mediaViewModel = mediaViewModel, photoUIState = photoUIState, videoUIState = videoUIState, onMediaItemClick = onMediaItemClick ) } @Composable fun ScreenContent( modifier: Modifier = Modifier, mediaViewModel: MediaViewModel, photoUIState: State<PhotoUIState>, videoUIState: State<VideoUIState>, onMediaItemClick: () -> Unit ) { val topBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() Scaffold( modifier = modifier .nestedScroll(topBarScrollBehavior.nestedScrollConnection), topBar = { TopAppBarContent(topBarScrollBehavior) } ) { contentPadding -> MediaScreenBody( contentPadding = contentPadding, mediaViewModel = mediaViewModel, photoUIState = photoUIState, videoUIState = videoUIState, onMediaItemClick = onMediaItemClick ) } } @Composable fun TopAppBarContent(scrollBehavior: TopAppBarScrollBehavior? = null) { TopAppBar( title = { Text( text = stringResource(id = R.string.app_name) ) }, colors = TopAppBarDefaults.topAppBarColors( containerColor = if (isSystemInDarkTheme()) cs_theme_dark_topBar else cs_theme_light_topBar, titleContentColor = Color.White ), scrollBehavior = scrollBehavior ) } @Composable fun MediaScreenBody( modifier: Modifier = Modifier, mediaViewModel: MediaViewModel, contentPadding: PaddingValues, photoUIState: State<PhotoUIState>, videoUIState: State<VideoUIState>, onMediaItemClick: () -> Unit, ) { val pagerState = rememberPagerState { 3 } var selectedTabIndex by rememberSaveable { mutableIntStateOf(0) } Column( modifier = Modifier .padding(contentPadding) .fillMaxSize() ) { TabRow( selectedTabIndex = selectedTabIndex, containerColor = if (isSystemInDarkTheme()) cs_theme_dark_topBar else cs_theme_light_topBar, contentColor = Color.White ) { tabs.forEachIndexed { index, tabData -> Tab( selected = index == selectedTabIndex, onClick = { selectedTabIndex = index }, text = { Text(text = tabData.title) } ) } } HorizontalPager( modifier = modifier.fillMaxSize(), state = pagerState ) { currentPage -> when (currentPage) { 0 -> { when (photoUIState.value.mediaPhotos) { is PhotoLoadingState.Loading -> LoadingScreen() is PhotoLoadingState.Success -> SuccessScreen( mediaList = (photoUIState.value.mediaPhotos as PhotoLoadingState.Success).photos, onDownloadClick = { val isSaved = mediaViewModel.saveMedia(it) }, onMediaItemClick = onMediaItemClick ) is PhotoLoadingState.Error -> ErrorScreen(onRetry = { mediaViewModel.loadPhotos() }) } } 1 -> { when (videoUIState.value.mediaVideos) { is VideoLoadingState.Loading -> LoadingScreen() is VideoLoadingState.Success -> SuccessScreen( mediaList = (videoUIState.value.mediaVideos as VideoLoadingState.Success).videos, onDownloadClick = {}, onMediaItemClick = onMediaItemClick ) is VideoLoadingState.Error -> ErrorScreen(onRetry = { mediaViewModel.loadVideos() }) } } else -> { val context = LocalContext.current Button(onClick = { Toast.makeText( context, "I'm working m third pager", Toast.LENGTH_LONG ).show() }) { Text(text = "Hello") } } } } } } 中直接调用它。但当内容滚动时,它会导致超过 40-50 次重新合成,情况变得更糟。这就是我尝试将代码移动到

MediaScreenBody()
-
MediaScreenBody()

	
android-jetpack-compose
2个回答
0
投票

切勿将视图模型传递给您的子可组合项。有一个回调来暗示事件并在该回调中使用您的视图模型。
  1. 在您的情况下,您可以避免将 viewmodel 传递给 MediaScreenBody() 方法并在 ScreenContent() 方法本身中使用 viewmodel。像这样:

val mediaViewModel: MediaViewModel = viewModel( factory = MediaViewModel.Factory ) val photoUIState = mediaViewModel.photoUIState.collectAsState() val videoUIState = mediaViewModel.videoUIState.collectAsState()

您可以使用最后两个回调再次从视图模型加载。

    在您倾向于使用视图模型的方法调用之外声明一个 lambda。有时直接在回调中使用视图模型可能会导致不必要的重组。示例如下:
  1. val onClickLambda = Remember

    Unit> { { // 视图模型访问 } }

    <() ->@Composable fun Test() { Button(onClick = onClickLambda) {} }


0
投票
已知错误

,最终已被修复 并发布于 fun MediaScreenBody( modifier: Modifier = Modifier, contentPadding: PaddingValues, onMediaItemClick: () -> Unit, onPhotoError: () -> Unit, onVideoError: () -> Unit )

请参阅
发行说明

© www.soinside.com 2019 - 2024. All rights reserved.