Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Daniel Galpin] Adventures in Navigation

[Daniel Galpin] Adventures in Navigation

Presentation from GDG DevFest Ukraine 2018 - the biggest community-driven Google tech conference in the CEE.

Learn more at: https://devfest.gdg.org.ua

__

Take a spin with the new Android Jetpack Navigation Components library announced at Google I/O. The Navigation Components let you keep all of your navigation information in one place and include support for Material components such as bottom navigation, the app drawer, and the overflow menu.

Dan will explore the basics and then dive into a series of more complex use cases. Learn about advanced topics such as deep-linking, leveraging Navigation to simplify modularization for instant apps and Dynamic App Delivery, using sub-graphs, manipulating the back-stack, sharing a ViewModel between navigation destinations and more. See what Navigation components can do for you!

Google Developers Group Lviv

October 13, 2018
Tweet

More Decks by Google Developers Group Lviv

Other Decks in Technology

Transcript

  1. Adventures in Navigation
    Dan Galpin
    @dagalpin

    View Slide

  2. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    Why Navigation

    View Slide

  3. Things weren't easy
    Fragment Transactions
    Deep Links Passing Arguments
    Error Prone Boilerplate
    Testing

    View Slide

  4. Things weren't consistent
    Deep Links
    Up and Back
    Navigation Drawer
    Bottom Navigation
    Menus

    View Slide

  5. Principles of Navigation

    View Slide

  6. Fixed Starting
    Destination

    View Slide

  7. Fixed Starting
    Destination

    View Slide

  8. Fixed Starting
    Destination*

    View Slide

  9. VS

    View Slide

  10. Up Navigation
    Traverses up the Hierarchy

    View Slide

  11. Up Navigation
    Traverses up the Hierarchy
    Parent Child

    View Slide

  12. Up Navigation
    Traverses up the Hierarchy
    Parent Child

    View Slide

  13. Up Navigation
    Traverses up the Hierarchy

    View Slide

  14. ???

    View Slide

  15. ???

    View Slide

  16. Up Navigation
    Traverses up the Hierarchy

    View Slide

  17. ==
    Within Your Task

    View Slide

  18. !=
    When Your Activity is Part of the Task of Another App

    View Slide

  19. View Slide

  20. Deep Linking

    View Slide

  21. Deep Linking

    View Slide

  22. Deep Linking

    View Slide

  23. Be Consistent

    View Slide

  24. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    A (quick) tour of the Navigation
    Component

    View Slide

  25. The Navigation Component
    // Main Navigation Component code
    implementation "android.arch.navigation:navigation-fragment:$version"
    // NavigationUI static methods to setup action/toolbars, drawers and menus
    implementation "android.arch.navigation:navigation-ui:$version"
    // Safe Args code generation plugin for type safety
    apply plugin: 'androidx.navigation.safeargs'
    // Test helpers
    androidTestImplementation "android.arch.navigation:navigation-testing:$nav_version"

    View Slide

  26. The Navigation Component
    // Main Navigation Component code
    implementation "android.arch.navigation:navigation-fragment-ktx:$version"
    // NavigationUI static methods to setup action/toolbars, drawers and menus
    implementation "android.arch.navigation:navigation-ui-ktx:$version"
    // Safe Args code generation plugin for type safety (no KTX version)
    apply plugin: 'androidx.navigation.safeargs'
    // Test helpers
    androidTestImplementation "android.arch.navigation:navigation-testing-ktx:$nav_version"

    View Slide

  27. Navigation Graph
    (New Resource)
    NavHostFragment
    (Layout)
    NavController
    (Java/Kotlin)
    NavHost

    View Slide

  28. start destination
    destination
    destination
    destination
    destination
    destination
    destination
    destination

    View Slide

  29. action
    action
    action
    action
    action
    action
    action
    action
    action
    action

    View Slide

  30. View Slide

  31. Navigation Graph
    (New Resource)
    NavHostFragment
    (Layout)
    NavController
    (Java/Kotlin)
    NavHost

    View Slide

  32. Navigation Graph
    (New Resource)
    NavHostFragment
    (Layout)
    NavController
    (Java/Kotlin)
    NavHost
    navController.navigate()

    View Slide

  33. NavHost
    NavController
    (Java/Kotlin)
    navController.navigate(R.id.in_game_dest)
    R.id.in_game_dest
    Navigation Graph
    (New Resource)
    NavHostFragment
    (Layout)

    View Slide

  34. NavHost
    NavController
    (Java/Kotlin)
    navController.navigate(R.id.win_action)
    R.id.win_action
    Navigation Graph
    (New Resource)
    NavHostFragment
    (Layout)

    View Slide

  35. ● Visualizes navigation paths
    The Navigation Component

    View Slide

  36. The Navigation Component
    ● Visualizes navigation paths
    ● Defines navigation in one place

    View Slide

  37. The Navigation Component
    ● Visualizes navigation paths
    ● Defines navigation in one place
    ● Reduces nav pattern boilerplate
    That's a lot of steps for a
    NavDrawer!

    View Slide

  38. The Navigation Component
    ● Visualizes navigation paths
    ● Defines navigation in one place
    ● Reduces nav pattern boilerplate
    ● Implements Material guidelines
    (including backstack)

    View Slide

  39. Getting Started

    View Slide

  40. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    General Guidance

    View Slide

  41. Fragment or
    Activity Destinations?

    View Slide

  42. It's possible to navigate to an Activity
    Terminal destination

    View Slide

  43. Activities for Global
    Navigation
    NavHost
    Global navigation

    View Slide

  44. Fragments for Content
    NavHost
    Content

    View Slide

  45. Benefits of Single
    Activity
    ● Single navigation graph
    ● Transition animations for property and
    views
    ● Activity ViewModels can be shared
    amongst fragments
    NavHost ViewModel
    LiveData
    LiveData
    LiveData

    View Slide

  46. Destinations or Actions?

    View Slide

  47. ● You can see them
    Use actions

    View Slide

  48. Use actions
    ● You can see them
    ● Your navigation graph will contain more
    information
    Transitions between
    destinations
    Argument passing
    Backstack manipulation

    View Slide

  49. Use actions
    ● You can see them
    ● Your navigation graph will contain more
    information
    ● You can use safe args
    Argument passing

    View Slide

  50. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    Safe Args

    View Slide

  51. Safe Args
    Code Generation Plugin
    Uses your Navigation Graph to
    ensure type safety

    View Slide

  52. ID's Are Used to Represent Lots of Things
    ● R.id.win_action // id for Action
    ● R.id.win_destination // id for Destination
    ● R.id.win_menu_item // id for Menu Item
    ● R.id.win_image_view // id for ImageView
    ● navController.navigate(R.id.win) // navigating to ¯\_(ツ)_/¯

    View Slide

  53. Using sensible naming conventions helps
    ● R.id.win_action // id for Action
    ● R.id.win_destination // id for Destination
    ● R.id.win_menu_item // id for Menu Item
    ● R.id.win_image_view // id for ImageView
    ● navController.navigate(R.id.win.action) // id for action

    View Slide

  54. navController.navigate(R.id.image_view)

    View Slide

  55. navController.navigate(R.id.action_register_to_match)
    R.id.action_register_to_match

    View Slide

  56. navController.navigate(RegisterDirections.actionRegisterToMatch())
    R.id.action_register_to_match

    View Slide

  57. val matchAction = RegisterDirections.actionRegisterToMatch()
    matchAction.setOpponent("User3466")
    navController.navigate(matchAction)
    Example with argument
    R.id.action_register_to_match

    View Slide

  58. val matchAction = RegisterDirections.
    actionRegisterToMatch("User3466")
    navController.navigate(matchAction)
    Example with argument without
    default
    R.id.action_register_to_match

    View Slide

  59. val args = MatchFragmentArgs.fromBundle(arguments)
    val opponent = args.opponent
    Match Fragment
    Fetching the arguments from
    the bundle

    View Slide

  60. Safe Args
    //build.gradle (project)
    classpath
    "android.arch.navigation:navigation-safe-args
    -gradle-plugin:$version"
    //build.gradle (app)
    apply plugin: 'androidx.navigation.safeargs'
    "Directions" for any
    destination with Actions,
    named after the class
    "Args" for every destination
    with argument(s)

    View Slide

  61. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    Navigation UI

    View Slide

  62. Up Button Overflow Menu Nav Drawer
    Bottom Nav

    View Slide

  63. Navigation Drawer
    Apps with five or more top-level destinations
    Apps with two or more levels of navigation hierarchy
    Quick navigation between unrelated destinations

    View Slide

  64. Start Destination
    Top Level Destinations

    View Slide

  65. Back Stack

    View Slide

  66. Message Detail
    Back Stack

    View Slide

  67. Back Stack

    View Slide

  68. Bottom Navigation
    Apps with three to five top-level destinations that
    need to be accessible anywhere in the app
    Mobile and Tablet only

    View Slide

  69. Start Destination

    View Slide

  70. Back Stack

    View Slide

  71. Back Stack

    View Slide

  72. Back Stack

    View Slide

  73. View Slide

  74. View Slide

  75. Activity
    Outer Navigation Host Fragment
    Inner Navigation Host Fragment

    View Slide

  76. Tabs
    Not supported by navigation since tabs don't change
    between destinations.

    View Slide

  77. xmlns:android="http://schemas.android.com/apk/res/android">
    android:id="@+id/rulesFragment"
    android:icon="@drawable/rules"
    android:title="@string/rules" />
    android:id="@+id/aboutFragment"
    android:icon="@drawable/android"
    android:title="@string/about" />

    View Slide

  78. Overflow Menu
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    super.onCreateOptionsMenu(menu, inflater)
    inflater.inflate(R.menu.overflow_menu, menu)
    MenuCompat.setGroupDividerEnabled(menu, true);
    }
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return NavigationUI.onNavDestinationSelected(item,
    findNavController())
    || super.onOptionsItemSelected(item)
    }

    View Slide

  79. Setup Bottom Navigation
    // In onCreate of Activity
    // Setup the NavDrawer by passing the NavigationView to NavigationUI
    NavigationUI.setupWithNavController(binding.bottomNav, navController)

    View Slide

  80. The Up Button - Fragment + Toolbar
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?): View? {
    ...
    val navController = findNavController()
    NavigationUI.setupWithNavController(binding.toolbar, navController)
    ...
    }

    View Slide

  81. The Up Button - Activity + ActionBar
    override fun onCreate(savedInstanceState: Bundle?) {
    ...
    val navController = this.findNavController(R.id.myNavHostFragment)
    NavigationUI.setupActionBarWithNavController(this,navController)
    ...
    }
    override fun onSupportNavigateUp(): Boolean {
    val navController = this.findNavController(R.id.myNavHostFragment)
    return NavigationUI.navigateUp(navController)
    }

    View Slide

  82. override fun onCreate(savedInstanceState: Bundle?) {
    ...
    NavigationUI.setupActionBarWithNavController(this, navController,
    drawerLayout)
    NavigationUI.setupWithNavController(navView, navController)
    ...
    }
    override fun onSupportNavigateUp(): Boolean {
    return NavigationUI.navigateUp(drawerLayout, navController)
    }
    Setup a NavDrawer

    View Slide

  83. public static void setupWithNavController(@NonNull final NavigationView navigationView, @NonNull
    final NavController navController) {
    navigationView.setNavigationItemSelectedListener(new OnNavigationItemSelectedListener() {
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    boolean handled = NavigationUI.onNavDestinationSelected(item, navController, true);
    if (handled) {
    ViewParent parent = navigationView.getParent();
    if (parent instanceof DrawerLayout) {
    ((DrawerLayout)parent).closeDrawer(navigationView);
    }
    }
    return handled;
    }
    });

    View Slide

  84. static boolean onNavDestinationSelected(@NonNull MenuItem item, @NonNull NavController
    navController, boolean popUp) {
    ...
    if (popUp) {
    builder.setPopUpTo(findStartDestination(navController.getGraph()).getId(), false);
    }
    NavOptions options = builder.build();
    ...
    popUp

    View Slide

  85. View Slide

  86. Activity vs. Fragment for
    Detail
    ● Is the toolbar global nav?
    ● Is the bottom nav global nav?
    ● Can we get the up button to function
    easily?

    View Slide

  87. NavHost NavHost

    View Slide

  88. Activity vs. Fragment for
    Detail
    ● Is the toolbar global nav?
    ○ No - it changes radically
    ● Is the bottom nav global nav?
    ○ Yes
    ● Can we get the up button to function
    easily?

    View Slide

  89. Setup Action Bar, Tool Bar
    // Setting up other fragments without CollapsingToolbar
    NavigationUI.setupWithNavController(toolbar, navController)
    // Setting up DetailFragment with CollapsingToolbar Navigation
    NavigationUI.setupWithNavController(collapsingToolbarLayout,
    binding.toolbar, navController)
    // No need to do anything else for up button

    View Slide

  90. Activity vs. Fragment for
    Detail
    ● Is the toolbar global nav?
    ○ No - it changes radically
    ● Is the bottom nav global nav?
    ○ Yes
    ● Can we get the up button to function
    easily?
    ○ Yes
    ● What about transitions?
    ○ Looks a little strange

    View Slide

  91. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    Shared Element Transitions

    View Slide

  92. Shared Elements

    View Slide

  93. fun selectPlayerProfile( playerName: String, view: ImageView) {
    val navController = view.findNavController()
    val extras = FragmentNavigatorExtras(
    view to playerName
    )
    navController.navigate(
    LeaderboardDirections.actionLeaderboardToUserProfile(playerName), extras)
    }
    Supporting Shared Elements in Navigation

    View Slide

  94. Shared Element Transitions
    // in user profile fragment
    val enterTransitionSet = TransitionSet()
    enterTransitionSet.addTransition(TransitionInflater.from(context)
    .inflateTransition(android.R.transition.move))
    sharedElementEnterTransition = enterTransitionSet
    // in leaderboard fragment
    postponeEnterTransition()
    recyclerView.getViewTreeObserver()
    .addOnPreDrawListener {
    startPostponedEnterTransition()
    true }
    val returnTransitionSet = TransitionSet()
    returnTransitionSet.addTransition(TransitionInflater.from(context)
    .inflateTransition(android.R.transition.move))
    sharedElementReturnTransition = returnTransitionSet

    View Slide

  95. Shared Element Transitions - Waiting for Images
    @BindingAdapter("sharedElementImageUrl")
    fun bindSharedImage(imageView: ImageView, url: String?) {
    Glide.with(fragment).load(url)
    .listener(object : RequestListener {
    override fun onResourceReady(_: Drawable?, _: Any?, _: Target?,
    _: DataSource?, _: Boolean): Boolean {
    fragment.startPostponedEnterTransition()
    return false
    }
    override fun onLoadFailed(e: GlideException?, _: Any?, _: Target?,
    _: Boolean): Boolean {
    fragment.startPostponedEnterTransition()
    return false
    }
    })
    .into(imageView)
    }

    View Slide

  96. Conditional Navigation

    View Slide

  97. Straight-forward
    val actionRegister =
    TitleScreenDirections.actionRegister()
    navController.navigate(actionRegister)

    View Slide

  98. Less so...
    ● Decide whether to go to win or lose
    screen
    ● Data not usually in the fragment
    ● Avoid having lots of navigation logic in
    activities/fragments

    View Slide

  99. Guide to App
    Architecture
    ● One way to do it, using Lifecycle
    libraries
    ● developer.android.com/jetpack/docs/g
    uide

    View Slide

  100. Fragment
    Data Layer
    ViewModel
    LiveData
    LiveData
    LiveData
    Does actual navigation
    Provides any non-transient data
    Holds data needed to make
    navigation decisions
    Communicated decisions
    back to fragment via
    observation
    Where all the conditional navigation
    decisions can be made

    View Slide

  101. Navigates
    User answers last question
    Fragment
    Data Layer
    ViewModel
    LiveData
    LiveData
    LiveData
    Takes the data such as
    score, difficulty, etc and
    decides whether it's a win or
    lose
    Communicates win/loss
    to Fragment

    View Slide

  102. LiveData to Navigate
    Problem
    ● LiveData holds data state
    ○ Ex. "This button is green"
    ● Data state != to an event
    ○ Ex. Anything that fires and is done
    ○ "Show this notification"
    ● Navigation is an event
    ○ You never stay in the "navigating
    to Win" state
    Fragment
    Data Layer
    ViewModel
    LiveData
    LiveData
    LiveData
    Communicates win/loss
    to Fragment

    View Slide

  103. View Slide

  104. Event (Wrapper around LiveData to only handle once)
    open class Event(private val content: T) {
    var hasBeenHandled = false
    private set // Allow external read but not write
    fun getContentIfNotHandled(): T? {
    return if (hasBeenHandled) {
    null
    } else {
    hasBeenHandled = true
    content
    }
    }
    fun peekContent(): T = content
    }

    View Slide

  105. Fragment - User answers last question
    // Call a ViewModel method from the Fragment when user finishes the quiz
    binding.quizFinishedButton.setOnClickListener {
    viewModel.quizFinished()
    }

    View Slide

  106. ViewModel - Decide win or lose
    // ViewModel and LiveData
    val navigateToWin = MutableLiveData>()
    val navigateToGameOver = MutableLiveData>()
    fun quizFinished() {
    //Do logic with score, rules, etc to see if game was won
    }

    View Slide

  107. ViewModel with LiveData Event - Communicate
    Navigation
    // ViewModel and LiveData
    val navigateToWin = MutableLiveData>()
    val navigateToGameOver = MutableLiveData>()
    fun quizFinished() {
    //Do logic with score, rules, etc to see if game was won
    if (wonGame) {
    navigateToWin.value = Event(score)
    } else {
    navigateToGameOver.value = Event(score)
    }
    }

    View Slide

  108. Fragment - Navigate!
    // Observer when navigation events happen
    viewModel.navigateToWin.observe(this, Observer {
    it.getContentIfNotHandled()?.let { score ->
    val action = InGameDirections.winAction()
    action.setScore(score)
    navController.navigate(action)
    }
    })
    // Similar observer for gameOverAction

    View Slide

  109. Only visible to logged in
    users
    Login Flow Example

    View Slide

  110. View Slide

  111. Login
    When I navigate or when my logged in state
    changes, check if I should be sent to the login
    flow.

    View Slide

  112. Login
    ● Use nested graph for Login flow

    View Slide

  113. Nested Graphs
    ● Good for sub-flows like login

    View Slide

  114. Nested Graphs
    ● Good for sub-flows like login
    ● Navigating to Nested Graphs will always
    send you to start destination
    Start Destination

    View Slide

  115. Login
    ● Use nested graph for Login flow
    ● Use global action

    View Slide

  116. Global Action
    ● Has a destination, but no starting point
    Normal action
    Global action

    View Slide

  117. Global Action
    ● Has a destination, but no starting point
    ● Can be used by any destination in the
    graph

    View Slide

  118. Global Action
    ● Has a destination, but no starting point
    ● Can be used by any destination in the
    graph
    ● An action not nested in a destination is a
    global action

    View Slide

  119. android:id="@+id/main_navigation"
    app:startDestination="@id/fragmentA">










    View Slide

  120. android:id="@+id/main_navigation"
    app:startDestination="@id/fragmentA">









    android:id="@+id/login"
    app:startDestination="@id/loginFragment">



    Login nested graph

    View Slide

  121. android:id="@+id/main_navigation"
    app:startDestination="@id/fragmentA">









    android:id="@+id/login"
    app:startDestination="@id/loginFragment">


    android:id="@+id/action_global_login"
    app:destination="@id/login" />

    Global action

    View Slide

  122. Login
    ● Use nested graph for Login flow
    ● Use global action
    ● Use shared Activity ViewModel

    View Slide

  123. ViewModel ViewModel ViewModel ViewModel ViewModel
    Activity ViewModel
    for shared UI data

    View Slide

  124. LiveData
    Activity
    ViewModel
    currentDestinationId:
    LiveData
    isLoggedIn:
    LiveData
    navigateToLogin:
    LiveData>
    Just mentioned how
    to set this up
    Depends on what you're
    doing to implement login
    You can use an
    onNavigatedListener

    View Slide

  125. OnNavigatedListener
    ● Called as you arrive at a destination
    ○ Includes current destination
    ● Useful for updating Navigation UI
    ● Remember to remove listener

    View Slide

  126. OnNavigatedListener
    // In Activity onCreate
    navigationListener = NavController.OnNavigatedListener {
    controller, destination ->
    // Redirect navigation here
    }
    navController.addOnNavigatedListener(navigationListener)
    // In Activity onDestroy
    navController.removeOnNavigatedListener(navigationListener)
    Redirect navigation

    View Slide

  127. Login
    ● Use nested graph for Login flow
    ● Use global action
    ● Tracking current destination with
    OnNavigatedListener
    ● Use popTo for correct login flow
    behavior

    View Slide

  128. Don't include this fragment in
    the back stack

    View Slide

  129. popUpTo

    android:id="@+id/back_to_login_action"
    app:popUpTo="@+id/loginFragment"
    app:popUpToInclusive="false" />

    Removes all on back stack until reaching
    "loginFragment", not including
    "loginFragment"

    View Slide

  130. Pops any and all intermediate screens
    off back stack

    View Slide

  131. When login finishes - pop entire graph off the back stack to go
    back to whatever was before...

    View Slide

  132. popUpTo with Global Action
    android:id="@+id/login"
    app:startDestination="@id/loginFragment">
    android:id="@+id/finish_login"
    app:popUpTo="@id/login"
    app:popUpToInclusive="true" />


    Global action - pops to whatever was on
    the back stack right before

    View Slide

  133. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    Deep Linking

    View Slide

  134. Explicit Deep Linking

    View Slide

  135. Creating a Deep Link Pending Intent
    val pendingIntent = NavDeepLinkBuilder(context!!)
    .setGraph(R.navigation.navigation)
    .setDestination(R.id.gameWonFragment)
    .createPendingIntent()

    View Slide

  136. Sibling
    Sibling
    Sibling
    Start Destination

    View Slide

  137. Selected Destination
    Start Destination

    View Slide

  138. View Slide

  139. Main Graph Start
    Destination
    Selected Destination
    Nested Graph Start
    Destination

    View Slide

  140. Implicit Deep Linking

    View Slide

  141. Creating our Link

    View Slide

  142. Deep Linking with an Argument
    android:id="@+id/user_profile"
    android:name="com.navsample.ui.UserProfile"
    android:label="fragment_user_profile"
    tools:layout="@layout/fragment_user_profile" >
    android:name="selectedUser"
    app:type="string" />


    View Slide

  143. Deep Linking with an Argument
    android:id="@+id/user_profile"
    android:name="com.navsample.ui.UserProfile"
    android:label="fragment_user_profile"
    tools:layout="@layout/fragment_user_profile" >
    android:name="selectedUser"
    app:type="string" />


    View Slide

  144. Deep Linking with an Argument
    android:id="@+id/user_profile"
    android:name="com.navsample.ui.UserProfile"
    android:label="fragment_user_profile"
    tools:layout="@layout/fragment_user_profile" >
    android:name="selectedUser"
    app:type="string" />


    View Slide

  145. Adding the Intent Filter to the AndroidManifest








    View Slide

  146. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    Instant Apps

    View Slide

  147. Instant Apps
    Native Android experience, no installation
    Downloads only needed modules

    View Slide

  148. base
    a b c
    instant
    instant
    installable
    installable
    Instant App Module Structure

    View Slide

  149. Instant App Module Structure
    base
    a b c
    installable
    nav_graph_a nav_graph_b nav_graph_c
    nav_graph_base
    None of these graphs should reference each other's ids

    View Slide

  150. Instant App Module Structure
    base
    a b c
    installable
    nav_graph_a nav_graph_b nav_graph_c
    nav_graph_base
    Installable main_nav_graph overrides base, but only for the
    installed app
    main_nav_graph
    main_nav_graph

    View Slide

  151. main_nav_graph.xml (installable)
    app:startDestination="@id/nav_graph_base">





    Includes all feature graphs

    View Slide

  152. main_nav_graph.xml (base)
    app:startDestination="@id/base_dest">

    android:id="@id/a_dest"
    app:data="https://navigation.instantappsample.com/a"
    app:action="android.intent.action.VIEW"/>


    Implicit Activity Deeplink for all
    features

    View Slide

  153. Instant App Module Structure
    base
    a b c
    installable
    nav_graph_a nav_graph_b nav_graph_c
    nav_graph_base
    To go from base to a,b and c in the installable app world...
    main_nav_graph
    main_nav_graph

    View Slide

  154. nav_graph_base.xml
    android:id="@+id/base_dest"
    app:startDestination="@id/base_fragment">
    android:id="@+id/base_fragment"
    android:name="com.instantappsamples.navigation.base.BaseFragment">
    android:id="@+id/action_base_to_a"
    app:destination="@+id/a_dest" />




    Action that triggers navigation
    Destination a_dest

    View Slide

  155. main_nav_graph.xml (installable)
    app:startDestination="@id/nav_graph_base">





    Includes nav_graph_a

    View Slide

  156. nav_graph_a.xml
    android:id="@id/a_dest"
    app:startDestination="@id/a_fragment">





    Destination a_dest (for installable app)

    View Slide

  157. Instant App Module Structure
    base
    a b c
    installable
    nav_graph_a nav_graph_b nav_graph_c
    nav_graph_base
    To go from base to a,b and c in the instant app world...
    main_nav_graph
    main_nav_graph

    View Slide

  158. nav_graph_base.xml
    android:id="@+id/base_dest"
    app:startDestination="@id/base_fragment">
    android:id="@+id/base_fragment"
    android:name="com.instantappsamples.navigation.base.BaseFragment">
    android:id="@+id/action_base_to_a"
    app:destination="@+id/a_dest" />




    Action that triggers navigation
    Destination a_dest

    View Slide

  159. main_nav_graph.xml (base)
    app:startDestination="@id/base_dest">

    android:id="@id/a_dest"
    app:data="https://navigation.instantappsample.com/a"
    app:action="android.intent.action.VIEW"/>


    Implicit Activity Deeplink, called a_dest
    Uri https://navigation.instantappsample.com/a

    View Slide

  160. nav_graph_a.xml
    android:id="@id/a_dest"
    app:startDestination="@id/a_fragment">





    Deep link destination for
    Uri https://navigation.instantappsample.com/a

    View Slide

  161. Instant App Module Structure
    base
    a b c
    installable
    nav_graph_a nav_graph_b nav_graph_c
    nav_graph_base
    To go from a to others features...
    main_nav_graph
    main_nav_graph

    View Slide

  162. nav_graph_b.xml



    <...>

    <...>

    Deep link destination for
    Uri https://navigation.instantappsample.com/b

    View Slide

  163. nav_graph_a.xml



    android:id="@+id/action_a_to_b"
    app:destination="@id/b_activity" />


    android:id="@+id/b_activity"
    app:data="https://navigation.instantappsample.com/b"
    app:action="android.intent.action.VIEW" />


    Implicit Activity Deeplink, called b_Activity
    Uri https://navigation.instantappsample.com/a

    View Slide

  164. More Adventure!
    Documentation
    developer.android.com/topic/libraries/architecture/navigation/
    DIY
    codelabs.developers.google.com/codelabs/android-navigation
    Samples
    github.com/googlesamples/android-sunflower
    github.com/googlesamples/android-architecture-components
    … NavigationBasicSample
    … GithubBrowserSample

    View Slide

  165. Proprietary + Confidential
    Proprietary + Confidential
    Proprietary + Confidential
    Thank You
    Dan Galpin
    @dagalpin

    View Slide