The Navigation Architecture Component Tutorial: Getting Started | Ray Wenderlich

In this tutorial, you’ll learn how to use the Navigation Architecture Component, which simplifies the implementation of navigation in Android apps.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/6014-the-navigation-architecture-component-tutorial-getting-started

Hi there, I’m following along but I got stuck on the step where you replace the Todo item in BookSearchFragment.kt inside the initAdapter() function with findNavController().navigate(R.id.actionBookDetails)
It’s telling me there’s a syntax error with findNavController() and that it expects arguments in the form of either findNavController(Activity, Int) or findNavController(View).
I added the import statement at the top import androidx.navigation.Navigation.findNavController which is slightly different than the code provided import androidx.navigation.fragment.findNavController
Importing androidx.navigation.fragment.findNavController fails with a syntax error…
How can I proceed?

Hi,

what is the syntax error that you’re getting with import androidx.navigation.fragment.findNavController?

Can you check that you have both:
implementation "android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha05"
and
implementation "android.arch.navigation:navigation-ui-ktx:1.0.0-alpha05"
dependencies added in build.gradle file for app module?

Thanks for that information! Apparently I missed that step at the beginning of the tutorial to add the correct dependencies (I only had navigation-fragment and not navigation-ui, and it was the non ktx version). It’s working correctly now, so thanks for the help!

No problem, enjoy the tutorial! :slight_smile:

Hi!

First of all - thanks for all the tutorials here on raywenderlich.com,
they are realy good and helps a beginner very much!

I have a question - does “the-navigation-architecture-component-tutorial”
work on Android 4.4.2? I see that its done for 5.0, but is it possible to run it
on my old phone (I use it instead of emulator)??

Regards
TompaD

@ikust Can you please help with this when you get a chance? Thank you - much appreciated! :]

Hi!

This tutorial works with Android 5.0 but can be modified slightly for Android 4.4.2.

You’ll have to change minSdkVersion to 19 in app module build.gradle. After doing that you should be able to follow the tutorial and run the app on your phone without any problems.

Best,
Ivan

Great! Thanks a lot!

Hi! Thanks for a great tutorial, really helped my grasp who to handle Logged in / out flows in my app.

Got a question regarding a warning I get when adding <author android:id="@+id/authorDetails" /> in my book_nav_graph. Any idea why?

Your final version does not have this warning, I cant seem to find where I missed anything when implementing the Dialog.

Thanks.

@ikust Do you have any feedback about this? Thank you - much appreciated! :]

Hi!
Thanks, I’m glad that you like the tutorial :]
Are you talking about Element author is not allowed here warning?

I wasn’t able to figure out why it’s showing (since custom navigator for the tag is defined). What did help in my case is doing File -> Invalidate Caches / Restart ... - after that warning was no longer shown and authorDetails destination is displayed under destinations on Navigation editor.

Best,
Ivan

Yes that was the exact bug. Restarting and busting cache fixed it. I filed an issue on the matter, its small but would be nice if the elements would be available compile time :slight_smile:

May I ask you a question related to back navigation. The MainActivity is clean at the moment, no awareness of view logic in fragments. The use case Im trying solve is if a user presses back on a screen (fragment) where users might have entered text and I want to intercept this action with a dialog asking if any changes should be discarded.

Then depending on users pressing Cancel in dialog they stay, or pressing Discard the navigation component handles that accordingly.

Is MainActivity::onBackPressed the only place of checking and handling that state available right now? Im not sure how that would be done either. Any ideas or further resources I could check?

In my current project, an Activity have its own ViewModel which is available in the related fragment and they communicate that way. But with one activity with many fragments as the recommended way forward is, I have a hard time figuring this out.

Thanks!

@ikust Can you please help with this when you get a chance? Thank you - much appreciated! :]

I agree :slight_smile:

I’ve managed to figure out a way you can handle back navigation in the fragment but it’s a bit “hacky”. Brace yourself :]

First create a new interface:

interface FragmentWithBack {

  fun onSupportNavigateUp(navigator: FragmentNavigator): Boolean {
    return navigator.popBackStack()
  }
}

Then implement a new Navigator that will replace the existing FragmentNavigator:

@Navigator.Name("fragment")
class FragmentWithBackNavigator(context: Context, 
    private val manager: FragmentManager, 
    containerId: Int) : FragmentNavigator(context, manager, containerId) {

  override fun popBackStack(): Boolean {
    Log.d("BackNavigator", "popBackStack")
    val fragment: FragmentWithBack? = manager.primaryNavigationFragment as? FragmentWithBack
    return fragment?.onSupportNavigateUp(this) ?: super.popBackStack()
  }
}

In your activity add the new navigator to nav controller and change onBackPressed implementation to:

  override fun onBackPressed() {
    if (findNavController(this, R.id.navHostFragment).currentDestination?.id == R.id.yourStartDestination) {
      super.onBackPressed()
    }
  }

Note that R.id.yourStartDestination should be the ID of the destination (or destinations) on which you wish to exit the app after pressing back.

Last thing, make the fragment where you wish to handle back implement FragmentWithBack interface and implement onSupportNavigateUp(FragmentNavigator) method. Return false if you wish to stay on the fragment or call navigator.popBackStack() and return its result.

I hope it helps!

Best,
Ivan

Hey Ivan,
Thanks for great tutorial, I think it’s the best piece on Android I’ve read this year.
I have a question about safe-args (plugin, lib), how do they fit in this tutorial scope? Are they still needed for sending data with action? If not whats the use case for them?

Thanks for any kind of clarification,
Keep up the good stuff!
Paweł

Hi Paweł,

thank you, I’m very glad to hear that! :]

Safe-args are not required for passing data with actions - you can do it by putting the data in a Bundle and passing it with actions when calling navigate(…) method - that’s how it’s done in the tutorial.

For the sake of simplicity we didn’t introduce them. What they provide is a type safe and convenient way to pass the arguments. For example instead of passing book argument to BookDetailsFragment this way:

  findNavController().navigate(
      R.id.actionShowEdition,
      BookDetailsViewModel.createArguments(book)
  )   

with safe-args you would use:

  findNavController().navigate(
      WorkDetailsFragmentDirections.ActionShowEdition()
          .setBook(book)
  )

And on BookDetailsViewModel side, instead of taking out the arguments directly from Bundle:

val book: Book? = arguments.getParcelable(BOOK_ARGUMENT)
this.book.postValue(book)

with safe-args you would use:

this.book.postValue(BookDetailsFragmentArgs.fromBundle(arguments).book)

Note that safe-args have some limitations - you can’t pass Serializable objects, only Parcelable.

All clear now:) Thanks for taking the time to explain:)
Can’t wait for your next tutorial!

1 Like

Final project crashes. Here’s the eror

Unable to start activity ComponentInfo{com.raywenderlich.android.bookmanstreasure/com.raywenderlich.android.bookmanstreasure.MainActivity}: android.view.InflateException: Binary XML file line #40: Binary XML file line #40: Error inflating class fragment

Hi,

can you check that fragment tag on line 40 in activity_main.xml looks exactly like this:

  <fragment
    android:id="@+id/navHostFragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true" />

This error is thrown if the fragment specified in the android:name property can’t be found.

Also, can you confirm you have the following dependencies added in build.gradle file for app module?

implementation "android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha05"
implementation "android.arch.navigation:navigation-ui-ktx:1.0.0-alpha05"

Best,
Ivan