
Ethereal Eric
Wanderer @ Thamani
Navigation works best when itās not mysterious but simple & transparent.Navigation is a core building block of every app. It sits on every user journeyāso if itās hard to reason about, that complexity leaks into every screen and feature.
Why?
In Nav2, navigation relied on imperative commands, which often acted as āfire-and-forgetā events. This created a synchronization gap: if a command was dropped during a configuration change or lifecycle shift, your UI state and your actual screen would drift apart. Nav3 eliminates this āsplit-brainā issue by treating the backstack as a declarative stateāa simple, observable list that serves as the single source of truth. The benefits of this approach are :- The backstack is a standard Kotlin list you own and manage, ensuring the UI always reflects your current data.
- Navigation transitions are reactive rather than command-based, meaning the UI automatically stays in sync with the underlying state.
- Complex stack manipulations like reordering, filtering, or clearing history use familiar list operations instead of restrictive API calls.
- State persistence is built-in, making it significantly easier to handle process death and deep linking without losing the userās place.
How?
Emit navigation events from the screen via callbacks
Letās take a lesson from SOLID principles and ensure navigation related functionality is not known by a particular screen (The UI should be dumb and only be responsible for displaying data - Single responsibility principle)Screens shouldnāt be aware what a backstack is, they only emit events and the owner of the backstack reacts accordingly.At Thamani we wanted to make navigation more clear, so we added a few extension functions for the team
Add NavEntryDecorators for the classic android/viewModel behavior
Introducing the āclassicā behavior youāre used to (SavedState + ViewModelStore)In Nav3, NavEntryDecorators are āwrappersā (middleware) that get applied to every NavEntry in your back stack. They let you attach the same behavior to all destinationsāwithout baking that behavior into each screen.
Conclusion
Thatās the whole navigation 3 flow- Navigation state is a mutable list to represent the backstack (imagine how much you can achieve with this kind of control)
- Forward navigation is just adding an item at the end of the list.
- Back navigation is just removing the last item from the list (again you can decide to play around with the list e.g removing 2 items when a user clicks the back button)
- NavDisplay renders via entryProvider
- Entry decorators restore the āclassicā ViewModel + SavedState behavior