如何在挂起函数中处理竞争条件(?)

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

我有一个带有

AsyncImage
的可组合函数,可以从服务器下载图像(我简化了函数以使其更容易理解):

@Composable
fun BannerReference(
    modifier: Modifier = Modifier,
    iconUrl: String? = null,
    iconUrlFromRes: Int? = null,
    onImageLoadingState: (State) -> Unit = {}
) {
        SubcomposeAsyncImage(
            modifier = Modifier
                .height(110.dp)
                .fillMaxSize(),
            model = iconUrl,
            contentScale = ContentScale.FillWidth,
            alignment = Alignment.TopCenter,
            onLoading = { onImageLoadingState.invoke(it) },
            onSuccess = { onImageLoadingState.invoke(it) },
            onError = { onImageLoadingState.invoke(it) },
            error = {
                Image(
                    painter = painterResource(id = iconUrlFromRes),
                    contentDescription = null,
                    contentScale = ContentScale.FillWidth,
                    alignment = Alignment.TopCenter
                )
            },
            contentDescription = "SubscribePageImage",
        )
}

因此有一个回调

onImageLoadingState
,我们在其中传递
AsyncImagePainter
。状态密封类可以是
Loading
Success
Error
。因此,我在另一个可组合函数中创建了多个
BannerReference
实例,并希望在其中至少一个的状态为
Loading
时添加加载程序。然后我在
Fragment
:

中创建这个屏幕
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? =
    ComposeView(requireContext()).apply {
        setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)

        setContent {
            val state = viewModel.uiState.collectAsState()
            ScreenWithSeveralBannerReferences(
                state = state.value,
                referralProgramsData = args.refData,
                imageLoadingState = {
                    viewModel.sendAction(ReferralListActions.ImagesLoadingStatuses(it))
                }
            )

            LaunchedEffect(Unit) {
                viewModel.effect.collect { effect ->
                    handleEffect(effect)
                }
            }
        }
    }

最后我在

ViewModel
挂起函数中处理这些状态:

private suspend fun processImageLoadingStatus(imageLoadingState: ImageLoadingStatuses) {

    imagesLoadingStatuses[imageLoadingState.index] = imageLoadingState.loadingState

    _uiState.emit(
        ReferralListState(
            LoadingState(
                showProgress = imagesLoadingStatuses.any { it.value is AsyncImagePainter.State.Loading },
                isTransparent = true
            )
        )
    )
}

问题是有时(我猜有加载错误时)下面的代码似乎无法正常工作,因为出现了无尽的加载程序。我认为当

BannerReference
的多个实例同时调用这些
onImageLoadingState
回调并且出现竞争条件(我不知道如何准确调用这种情况)并且一个或多个回调不执行时,就会发生这种情况。由于错误状态的回调不会被调用,所以加载器不会被隐藏。

            onLoading = { onImageLoadingState.invoke(it) },
            onSuccess = { onImageLoadingState.invoke(it) },
            onError = { onImageLoadingState.invoke(it) },

请您告诉我如何处理同时调用 onImageLoadingState 并且有时似乎没有执行的情况?

android kotlin asynchronous android-jetpack-compose
© www.soinside.com 2019 - 2024. All rights reserved.