Nav3 Router allows passing typed results back to a caller. Results are addressed by their type and are stored in a saveable store, making them durable across configuration changes and process death.
1. Define a Serializable Result Type
@Serializable
data class SelectedColor(val argb: Long)
2. Producing a Result
From the child screen, use popWithResult(value) to return a value and pop, or sendResult(value) to return a value without popping.
// Inside a screen entry
ColorPickerScreen(onPick = { argb -> router.popWithResult(SelectedColor(argb)) })
3. Consuming a Result
Durable Consumption (Recommended)
Use registerForResult<T> in a ViewModel or DisposableEffect. This is the only method that survives process death because it re-attaches to the saveable store.
class HomeViewModel(private val router: Router<Screen>) : ViewModel() {
private val pickColor = router.registerForResult<SelectedColor>(
onResult = { selected -> /* handle result */ },
onCancelled = { /* handle cancel */ }
)
fun pickColor() = router.push(Screen.ColorPicker)
override fun onCleared() = pickColor.dispose()
}
Ephemeral Consumption
The following methods are convenient but do not survive process death (they are captured at the call site):
pushForResult<T>(screen) { result -> ... }: One-call ergonomic form.openForResult<T> { screen }: A suspend function that returns the result or null.resultFlow<T>(): A cold Flow of results.
// Ephemeral example
@OptIn(EphemeralResultApi::class)
val selected: SelectedColor? = router.openForResult { Screen.ColorPicker }