PredictiveBackHandler

Functions summary

Unit
@Composable
PredictiveBackHandler(
    enabled: Boolean,
    onBack: suspend (progress: Flow<BackEventCompat>) -> Unit
)

An effect for handling predictive system back gestures.

Functions

PredictiveBackHandler

@Composable
fun PredictiveBackHandler(
    enabled: Boolean = true,
    onBack: suspend (progress: Flow<BackEventCompat>) -> Unit
): Unit

An effect for handling predictive system back gestures.

This effect registers a callback to receive updates on the progress of system back gestures as a Flow of BackEventCompat.

The onBack lambda should be structured to handle the start, progress, completion, and cancellation of the gesture:

PredictiveBackHandler { progress: Flow<BackEventCompat> ->
// This block is executed when the back gesture begins.
try {
progress.collect { backEvent ->
// Handle gesture progress updates here.
}
// This block is executed if the gesture completes successfully.
} catch (e: CancellationException) {
// This block is executed if the gesture is cancelled.
throw e
} finally {
// This block is executed either the gesture is completed or cancelled.
}
}

The handler is registered once and stays attached for the lifetime of the LifecycleOwner. Its OnBackPressedCallback.isEnabled state automatically follows the lifecycle: it becomes enabled when the lifecycle is at least Lifecycle.State.STARTED and disabled otherwise.

Precedence

If multiple PredictiveBackHandler are present in the composition, the one that is composed last among all enabled handlers will be invoked.

Usage

It is important to call this composable unconditionally. Use the enabled parameter to control whether the handler is active. This is preferable to conditionally calling PredictiveBackHandler (e.g., inside an if block), as conditional calls can change the order of composition, leading to unpredictable behavior where different handlers are invoked after recomposition.

Timing Consideration

There are cases where a predictive back gesture may be dispatched within a rendering frame before the enabled flag is updated, which can cause unexpected behavior (see b/375343407, b/384186542). For example, if enabled is set to false, a gesture initiated in the same frame may still trigger this handler because the system sees the stale true value.

Legacy Behavior

To restore the legacy add/remove behavior, set ActivityFlags.isOnBackPressedLifecycleOrderMaintained to false. In legacy mode, the handler is added on Lifecycle.Event.ON_START and removed on Lifecycle.Event.ON_STOP, which may change dispatch ordering across lifecycle transitions.

import androidx.activity.BackEventCompat
import androidx.activity.compose.BackHandler
import androidx.activity.compose.PredictiveBackHandler
import androidx.compose.material.TextField
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember

var text by remember { mutableStateOf("") }

TextField(value = text, onValueChange = { text = it })

PredictiveBackHandler(text.isNotEmpty()) { progress: Flow<BackEventCompat> ->
    callback.preparePop()
    try {
        progress.collect { backEvent -> callback.updateProgress(backEvent.progress) }
        callback.popBackStack()
    } catch (e: CancellationException) {
        callback.cancelPop()
    }
}
Parameters
enabled: Boolean = true

Controls whether this handler is active. Important: Due to the timing issue described above, a gesture starting immediately after enabled is set to false may still trigger this handler.

onBack: suspend (progress: Flow<BackEventCompat>) -> Unit

The suspending lambda to be invoked by the back gesture. It receives a Flow that can be collected to track the gesture's progress.