Jetpack compose button action onClick leak

Viewed 407

we've encountered a problem with Jetpack Compose button actions leaking. We provide a class with resources (e.g strings, colors, and BUTTON ACTIONS):

data class CameraOnBoardingComposeViewResources(val title: String, val buttonTitle: String, val buttonAction: () -> Unit)

This data class is created in the fragment like so:

val resources = CameraOnBoardingComposeViewResources(
    "Title", "ButtonTitle"
) { navigate() }

And in our composable we use those resources like so:

@Composable
fun composeOnBoardingView(resources: CameraOnBoardingComposeViewResources) {
    Surface(
        shape = RoundedCornerShape(4.dp),
        color = colorResource(R.color.idenfyMainColorV2),
        modifier = Modifier
            .height(42.dp)
            .padding(start = 16.dp, end = 16.dp)
            .clickable(onClick = resources.buttonAction)
            .fillMaxWidth()
    )
}

The problem is that buttonAction leaks. How can we avoid this leak, should we somehow dispose of it, or do we need to change this architecture a bit?

EDIT After CommonsWare

Ok, I’ve located the problem, and it is indeed inside the composeOnBoardingView composable. It’s this code snippet:

val currentInstructionDescription: MutableState<String> = remember {
   mutableStateOf("")
}

val progress = remember { mutableStateOf(0.0f) }

val handler = Handler(Looper.getMainLooper())
exoPlayer?.apply {
    val runnable = object : Runnable {
        override fun run() {
            progress.value =
                exoPlayer.currentPosition.toFloat() / exoPlayer.duration.toFloat()
            currentInstructionDescription.value = InstructionsDescriptionBuilder.build(
                context,
                (resources.documentCenterImageUiViewModel as OnBoardingCenterImageUIViewModel.DocumentResource).step,
                exoPlayer.currentPosition.toInt() / 1000
            )
            handler.postDelayed(this, 1000)
        }
    }
    handler.post(runnable)
}

I tried disposing the handler like this:

val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current

DisposableEffect(lifecycleOwner) {
    onDispose {
        handler.removeCallbacksAndMessages(null)
    }
}

But that did not solve the problem. Any ideas?

EDIT The issue is solved thanks CommonsWare! We switched to the LaunchedEffect and coroutines for an every-second in-composition timer, rather than Handler

0 Answers
Related