Using Navigation component in a large multi-module app
David Vávra
David Vávra
Twitter: @vavradav
Why to use Jetpack Navigation?
Air Bank Germany app architecture
Where to put navigation XML?
How to navigate from ViewModels?
NavigationCommand.kt
sealed class NavigationCommand {
data class To(val directions: NavDirections): NavigationCommand()
object Back: NavigationCommand()
data class BackTo(val destinationId: Int): NavigationCommand()
object ToRoot: NavigationCommand()
}
BaseViewModel.kt
// Command is SingleLiveEvent: http://bit.ly/arch-blueprints
val navigationCommands = Command<NavigationCommand>()
fun navigate(directions: NavDirections) {
navigationCommands.postValue(NavigationCommand.To(directions))
}
BaseFragment.kt
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
vm.navigationCommands.observe { command ->
when (command) {
is NavigationCommand.To ->
findNavController().navigate(command.directions)
…
CardListViewModel.kt
navigate(CardListFragmentDirections.cardDetail(cardId))
How to use arguments in ViewModels?
BaseFragment.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
vm.setArguments(arguments)
vm.loadData()
}
}
CardDetailViewModel.kt
override fun loadData() {
val cardId = CardDetailFragmentArgs.fromBundle(args).cardId
load(cardsRepository.getCard(cardId)) {
…
How to show a login screen with deep links?
Documentation on conditional navigation
MainActivity.kt
override fun onStart() {
super.onStart()
if (sessionRepository.isLoggedOut()) {
startActivity<LoginActivity>()
finish()
}
}
MainActivity.kt
val intent = Intent(this, LoginActivity::class.java)
intent.putExtra("deepLinkExtras", this.intent.extras)
startActivity(intent)
finish()
LoginActivity.kt
val intent = Intent(this, MainActivity::class.java)
intent.putExtras(this.intent.getBundleExtra("deepLinkExtras"))
startActivity(intent)
finish()
How to navigate back with a result?
NavigationResult.kt
interface NavigationResult {
fun onNavigationResult(result: Bundle)
}
Documentation: shared ViewModel
BaseActivity.kt
fun navigateBackWithResult(result: Bundle) {
val childFragmentManager = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)?.childFragmentManager
var backStackListener: FragmentManager.OnBackStackChangedListener by Delegates.notNull()
backStackListener = FragmentManager.OnBackStackChangedListener {
(childFragmentManager?.fragments?.get(0) as NavigationResult).onNavigationResult(result)
childFragmentManager.removeOnBackStackChangedListener(backStackListener)
}
childFragmentManager?.addOnBackStackChangedListener(backStackListener)
navController().popBackStack()
}
How to plug in a complex screen with a lot of animations?
Our dashboard
DashboardFragment
TL;DR
Thank you