Side Effect: Disposable Effect - devrath/ComposeAlchemy GitHub Wiki

About Disposable Effect

  • Disposable effect is a composable function that is executed when the composable function is first loaded/rendered and it gets disposed of when the composable is removed from the UI hierarchy.
  • This is useful when some clean-up operations need to be done when the composable is not in the UI hierarchy.
  • Example listeners and animations.
  • Use cases of this
    • Adding and removing event listeners
    • Starting and stopping animations
    • Bind and unbinding sensor resources such as Camera, LocationManager, etc
    • Managing database connections

Disposable Effect: Example-1

  • Observing the lifecycle changes in the composable
@Composable
fun TypeDisposableEffectDemo2Screen(modifier: Modifier = Modifier) {

    val lifecycleOwner = LocalLifecycleOwner.current
    val lifecycle = lifecycleOwner.lifecycle

    DisposableEffect(lifecycle) {
        // Create the observer
        val observer = LifecycleEventObserver { source , event ->
            when(event){
                Lifecycle.Event.ON_CREATE -> println("ON_CREATE is invoked")
                Lifecycle.Event.ON_START -> println("ON_START is invoked")
                Lifecycle.Event.ON_RESUME -> println("ON_RESUME is invoked")
                Lifecycle.Event.ON_PAUSE -> println("ON_PAUSE is invoked")
                Lifecycle.Event.ON_STOP -> println("ON_STOP is invoked")
                Lifecycle.Event.ON_DESTROY -> println("ON_DESTROY is invoked")
                Lifecycle.Event.ON_ANY -> println("ON_ANY is invoked")
            }
        }
        // Add the observer to lifecycle
        lifecycle.addObserver(observer)

        onDispose {
            // Remove the observer from lifecycle
            lifecycle.removeObserver(observer)
        }
    }
}

Disposable Effect: Example-2

  • Launching a Job and canceling in a composable

Output

<!------------------ When the screen is first loaded ------------------------!>
Root composable composition occurs
Column composable composition occurs
DisposableEffect scope is invoked
Timer is still working 1
Timer is still working 2
Timer is still working 3
Timer is still working 4
<!----- When we press the back button so composable is destroyed ------------!>
Dispose invoked

Observation

  • Note all the composables are composed only then the DisposableEffect scope is entered
  • When we press the back button composables are destroyed, note now the Dispose is triggered from the DisposableEffect

Code

@Composable
fun TypeDisposableEffect(navController: NavHostController) {

    val timeTaken = remember{ mutableIntStateOf(0) }

    println("Root composable composition occurs")

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(10.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {

        println("Column composable composition occurs")

        DisposableEffect(Unit) {

            println("DisposableEffect scope is invoked")

            val scope = CoroutineScope(Dispatchers.Default)
            val job = scope.launch {
                while (timeTaken.value<4) {
                    delay(1000)
                    timeTaken.value += 1
                    println("Timer is still working ${timeTaken.value}")
                }
            }

            onDispose {
                job.cancel()
                println("Dispose invoked")
            }
        }

    }

}