Implementing Back button press handler in Jetpack Compose

How to handle back button press in jetpack compose android.

In this post, I will demonstrate how to manage the back press event in Android 📱 when building your apps with Jetpack Compose.

Jetpack compose icon

Update:
Now it is very easy to handle back press in compose, just use the BackHandler composable fun as describe bellow.

import androidx.activity.compose.BackHandler

BackHandler(enable = true) {
// handle back press
}

You can continue reading post to gain knowledge about android back press handle logic.

In order to handle the back button press event in Android, we need to add OnBackPressedCallback to OnBackPressedDispatcher.

Let's define a CompositionLocal for composable functions to implicitly pass the
OnBackPressedDispatcherOwner (which holds an OnBackPressedDispatcher) across the composable functions.


private val localBackPressedDispatcher = staticCompositionLocalOf<OnBackPressedDispatcherOwner?> { null }

staticCompostionLocalOf<T> returns a providableCompostionLocal object,
which is key and provides a value for all the composable functions that are
called from within the lambda passed to CompositionLocalProvider(). By writing
localBackPressedDispatcher.current, we get access to the value associated with
this key.

Now you will write the OnBackPressedHandler composable function to register an
action that will be executed whenever the back button is pressed.

@Composable
internal fun OnBackPressedHandler(
    onBackPressed: () -> Unit,
) {
    CompositionLocalProvider(
        localBackPressedDispatcher provides LocalLifecycleOwner.current as ComponentActivity
    ) {
        Handler(onBackPressed)
    }
}

Here, provides is an infix function that associates a value with a key and
returns a ProvidedValue object. You can pass multiple ProvidedValues if you
want to implicitly pass more than one value to composable functions. In our
case, we want to attach an OnBackPressedDispatcherOwner object. We do this in
two steps. First, we get the LifecycleOwner and then cast it into
ComponentActivity (yeah, LifecycleOwner and OnBackPressedDispatcherOwner are
the objects because ComponentActivity implements both). 

Now you will write Handler composable function.

 
@Composable
fun Handler(onBackPressed: () -> Unit) {
    val dispatcher = (localBackPressedDispatcher.current ?: return).onBackPressedDispatcher

    DisposableEffect(dispatcher) {
        val callback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                onBackPressed()
            }
        }
        dispatcher.addCallback(callback)

        onDispose() {
            callback.remove()
        }
    }
}

DisposableEffect

JetPack composition offers a list of events that can be triggered at specific
points in the lifecycle called effects.

The disposable effect is an effect that requires cleanup. In our case, we
added a callback to the dispatcher within the disposable effect. Along with defining an action for the onDispose event, we also defined its key dispatcher
as a key for this effect. So when this disposable effect leaves the
composition or recomposes with another key, it fires what is inside the
onDispose. So this way, it automatically removes the callback from any
dispatcher.

Learn more about side effects in jetpack compose

The Complete code to register on back-pressed action

 val localBackPressedDispatcher = staticCompositionLocalOf<OnBackPressedDispatcherOwner?> { null }


// register onBackPressedaction

@Composable
fun OnBackButtonPress(onBackPressed: () -> kotlin.Unit) {
    CompositionLocalProvider(localBackPressedDispatcher provides LocalLifecycleOwner.current as ComponentActivity) {
        Handler (onBackPressed)
    }
}

@Composable
fun Handler(onBackPressed: () -> Unit) {
    val dispatcher = (localBackPressedDispatcher.current ?: return).onBackPressedDispatcher

    DisposableEffect(dispatcher) {
        val callback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                onBackPressed()
            }
        }
        dispatcher.addCallback(callback)

        onDispose() {
            callback.remove()
        }
    }
}
 
Share this Post

Leave a Reply

Your email address will not be published. Required fields are marked *