Эта статья не пошаговая инструкция, в ней опущены детали реализации, чтобы сосредоточить внимание на ключевых моментах. В интернете есть немало

Сразу скажу, библиотеку безусловно считаю полезной и не исключаю возможности неверного использования, но, пожалуй, я перепробовал всё прежде чем писать эту статью.
Итак, вот сценарии, при реализации которых ожидания по функционалу не совпали с реальностью в реализации:
- переключение между пунктами меню в navigation drawer
- открытие новой Activity со своим графом навигации
- передача параметров в startDestination
Переключение между пунктами меню
Это одна из тех функций, которые повлияли на решение использовать Navigation Component.
Нужно всего лишь сделать одинаковыми id пунктов меню
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      tools:showIn="navigation_view">
    <group android:checkableBehavior="single">
        <item
                android:id="@+id/importFragment"
                android:icon="@drawable/ic_menu_camera"
                android:title="Import"/>
        <item
                android:id="@+id/galleryFragment"
                android:icon="@drawable/ic_menu_gallery"
                android:title="Gallery"/>
        <item
                android:id="@+id/slideshowFragment"
                android:icon="@drawable/ic_menu_slideshow"
                android:title="Slideshow"/>
        <!-- Остальная часть меню -->
и id экранов (destination в графе навигации)
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/mobile_navigation"
            app:startDestination="@id/importFragment">
    <fragment
            android:id="@+id/importFragment"
            android:name="com.xiii.navigationapplication.ImportFragment"
            android:label="fragment_import"
            tools:layout="@layout/fragment_import"/>
    <fragment
            android:id="@+id/galleryFragment"
            android:name="com.xiii.navigationapplication.GalleryFragment"
            android:label="fragment_gallery"
            tools:layout="@layout/fragment_gallery"/>
    <fragment
            android:id="@+id/slideshowFragment"
            android:name="com.xiii.navigationapplication.SlideshowFragment"
            android:label="fragment_slideshow"
            tools:layout="@layout/fragment_slideshow"/>
</navigation>
затем нужно связать меню с контроллером навигации:
class MainActivity : AppCompatActivity() {
    private val navController by lazy(LazyThreadSafetyMode.NONE) {
        Navigation.findNavController(this, R.id.nav_host_fragment)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        // предоставим управление "гамбургером" в toolbar
        NavigationUI.setupWithNavController(toolbar, navController, drawer_layout)
        // связывание контроллера навигации и меню
        nav_view.setupWithNavController(navController)
    }
    // добавим поддержку кнопки назад
    override fun onSupportNavigateUp() = navController.navigateUp()
}
Навигация в меню заработала — ну разве не чудо?!

Обратите внимание на «гамбургер» (иконка меню), при переключении между пунктами меню он меняет своё состояние на кнопку «назад». Такое поведение показалось непривычным (привычное — как в приложении play market) и, какое-то время, я пытался разобраться, что же сделал не так?
Всё так! Перечитав документацию по принципам навигации (а именно: пункты два и три), понял, что «гамбургер» показывается только для startDestination, вернее так: кнопка «назад» показывается для всех, кроме startDestination. Ситуацию можно поменять применив различные уловки в подписке (addOnNavigatedListener()) на изменение destination, но их даже описывать не стоит. Работает так, нужно смириться.
Открытие новой Activity
Activity может выступать в качестве navigation host и, в то же время, в графе навигации может выступать в роли одного из destination. Открытие Activity без вложенного графа навигации работает как ожидается, то есть вызов:
navController.navigate(R.id.editActivity)осуществит переход (как в случае с фрагментами) и откроет запрошенную Activity.
Гораздо интереснее рассмотреть случай, когда целевая Activity сама выступает в роли navigation host, то есть вариант 2 из документации:

В качестве примера давайте рассмотрим Activity для добавления заметки. В ней будет основной фрагмент с полями ввода EditFragment, он в графе навигации будет startDestination. Давайте положим, что при редактировании нам нужно прикрепить фото, для этого будем переходить к PhotoFragment для получения снимка с камеры. Граф навигации будет выглядеть так:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/edit_navigation"
            app:startDestination="@id/editFragment">
    <fragment
            android:id="@+id/editFragment"
            android:name="com.xiii.navigationapplication.ui.edit.EditFragment"
            android:label="fragment_edit"
            tools:layout="@layout/fragment_edit">
        <action
                android:id="@+id/action_editFragment_to_photoFragment"
                app:destination="@id/photoFragment"/>
    </fragment>
    <fragment
            android:id="@+id/photoFragment"
            android:name="com.xiii.navigationapplication.ui.edit.PhotoFragment"
            android:label="fragment_photo"
            tools:layout="@layout/fragment_photo"/>
</navigation>
EditActivity мало отличается от MainActivity. Основное отличие в том, что на EditActivity нет меню:
class EditActivity : AppCompatActivity() {
    private val navController by lazy(LazyThreadSafetyMode.NONE) {
        Navigation.findNavController(this, R.id.nav_host_fragment)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_edit)
        setSupportActionBar(toolbar)
        // предоставим управление кнопкой "Назад" в toolbar
        NavigationUI.setupWithNavController(toolbar, navController)
    }
    override fun onSupportNavigateUp() = navController.navigateUp()
    fun takePhoto(view: View) {
        navController.navigate(R.id.action_editFragment_to_photoFragment)
    }
}
Activity открывается, навигация внутри неё работает:

Опять обратим внимание на кнопку навигации в toolbar — на стартовом EditFragment нет кнопки «Назад к parent Activity» (а хотелось бы). С точки зрения документации, тут всё законно: новый граф навигации, новое значение startDestination, на startDestination не показывается кнопка «Назад», конец.
Для тех, кому хочется вернуть привычное поведение c parent activity, сохранив при этом функционал переключения между фрагментами, могу предложить такой
<activity android:name=".EditActivity"
              android:parentActivityName=".MainActivity"
              android:theme="@style/AppTheme.NoActionBar">
    <!-- Parent activity meta-data to support 4.0 and lower -->
    <meta-data
              android:name="android.support.PARENT_ACTIVITY"
              android:value=".MainActivity" />
</activity>
class EditActivity : AppCompatActivity() {
    private val navController by lazy(LazyThreadSafetyMode.NONE) {
        Navigation.findNavController(this, R.id.nav_host_fragment)
    }
    private var isStartDestination = true
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_edit)
        setSupportActionBar(toolbar)
        val startDestinationId = navController.graph.startDestination
        // будем принудительно подменять id, чтобы NavigationUI.ActionBarOnNavigatedListener не пытался скрыть кнопку
        // при этом для всех остальных destination будем предоставлять оригинальный startDestination
        navController.addOnNavigatedListener { controller, destination ->
            isStartDestination = destination.id == startDestinationId
            // R.id.fake_start_destination этот id вручную определён для семантики и обеспечения уникальности
            controller.graph.startDestination = if (isStartDestination) R.id.fake_start_destination else startDestinationId
        }
        // предоставим управление кнопкой "Назад" в toolbar
        NavigationUI.setupActionBarWithNavController(this, navController)
    }
    override fun onSupportNavigateUp(): Boolean {
        // на startDestination не будем использовать навигацию от Navigation Component
        return if (isStartDestination) super.onSupportNavigateUp() else navController.navigateUp()
    }
    fun takePhoto(view: View) {
        navController.navigate(R.id.action_editFragment_to_photoFragment)
    }
}
Подписка нужна для того, чтобы для NavigationUI.ActionBarOnNavigatedListener все destination не являлись startDestination. Таким образом NavigationUI.ActionBarOnNavigatedListener не будет скрывать кнопку навигации (за деталями стоит обратиться к исходникам). Добавим к этому обработку onSupportNavigateUp() штатным образом на startDestination и получим то, что хотелось.
Стоит сказать, что решение это далеко от идеала хотя бы потому, что это неочевидное вмешательство в поведение библиотеки. Полагаю, могут возникнуть проблемы в случае использования deep links (ещё не проверял).
Передача параметров в startDestination
В Navigation Component есть механизм передачи параметров от одного destination другому. Есть даже инструмент для обеспечения безопасности типов за счёт кодогенерации (неплохо).
Сейчас мы разберём случай, из-за которого я не смог поставить твёрдую пятёрку этому функционалу.
Вернёмся к EditActivity, достаточно привычный сценарий, когда одна Activity используется для создания и редактирования объектов. При открытии объекта для редактирования в Activity нужно передать, например, id объекта — давайте сделаем это штатным образом:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/edit_navigation"
            app:startDestination="@id/editFragment">
    <argument
            android:name="id"
            app:argType="integer"/>
    <fragment
            android:id="@+id/editFragment"
            android:name="com.xiii.navigationapplication.ui.edit.EditFragment"
            android:label="fragment_edit"
            tools:layout="@layout/fragment_edit">
        <action
                android:id="@+id/action_editFragment_to_photoFragment"
                app:destination="@id/photoFragment"/>
    </fragment>
    <fragment
            android:id="@+id/photoFragment"
            android:name="com.xiii.navigationapplication.ui.edit.PhotoFragment"
            android:label="fragment_photo"
            tools:layout="@layout/fragment_photo"/>
</navigation>
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/mobile_navigation"
            app:startDestination="@id/importFragment">
    <fragment
            android:id="@+id/importFragment"
            android:name="com.xiii.navigationapplication.ImportFragment"
            android:label="fragment_import"
            tools:layout="@layout/fragment_import">
        <action
                android:id="@+id/add"
                app:destination="@id/editActivity">
            <argument
                    android:name="id"
                    app:argType="integer"
                    android:defaultValue="0"/>
        </action>
        <action
                android:id="@+id/edit"
                app:destination="@id/editActivity">
            <argument
                    android:name="id"
                    app:argType="integer"/>
        </action>
    </fragment>
    <fragment
            android:id="@+id/galleryFragment"
            android:name="com.xiii.navigationapplication.GalleryFragment"
            android:label="fragment_gallery"
            tools:layout="@layout/fragment_gallery"/>
    <fragment
            android:id="@+id/slideshowFragment"
            android:name="com.xiii.navigationapplication.SlideshowFragment"
            android:label="fragment_slideshow"
            tools:layout="@layout/fragment_slideshow"/>
    <activity
            android:id="@+id/editActivity"
            android:name="com.xiii.navigationapplication.EditActivity"
            android:label="activity_edit"
            tools:layout="@layout/activity_edit"/>
</navigation>
val direction = ImportFragmentDirections.edit(123 /* id заметки */)
navController.navigate(direction)
class EditFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        // работает во остальных случаях, когда fragment не создаётся в качестве startDestination
        // val id = EditFragmentArgs.fromBundle(arguments)
        val id = EditFragmentArgs.fromBundle(requireActivity().intent.extras)
        return inflater.inflate(R.layout.fragment_edit, container, false)
    }
}
Вы, наверняка, обратили внимание на особенности получения параметров в EditFragment. Так работает, потому что edit action (из пункта 1) передаёт аргументы в EditActivity, а она, в свою очередь, почему-то
Пожалуй, наибольшая сложность возникнет при одновременном использовании в качестве startDestination и обычного destination. То есть, при переходе и передаче параметров в startDestination из любого другого destination этого графа, фрагменту придётся самостоятельно определять, откуда извлекать параметры: из arguments или из intent.extras. Это нужно иметь ввиду при проектировании переходов с передачей параметров.
Резюмируя, хочу отметить, что сам не перестал использовать библиотеку и, несмотря на перечисленные
Благодарю за внимание. Рабочего Вам кода!
Исходники для статьи размещены на GitHub.
Комментарии (11)
 - Logos_Intellect08.11.2018 20:20- Google, как бы, намекает на использование подхода Single Activity  - XIII-th Автор08.11.2018 20:51- Это верно, но мне хотелось разделить логику просмотра и редактирования, чтобы не перегружать одну Activity элементами, которые нужны «не всем». 
 Рассмотрим, к примеру, toolbar — это общий компонент для всех фрагментов. Одни фрагменты
 (фрагменты списков) захотят видеть в нём поиск, другим нужно будет показывать сжимающуюся картинку (инфо фрагменты), а третьим и вовсе захочется встроить в toolbar поле ввода (фрагменты редактирования). Реализовав всё это в одной activity, мы получим монстр-toolbar/actvity со всеми вытекающими последствиями.
 Такой подход имеет право на жизнь, но мне привычнее жить с разделением ответственности. - Logos_Intellect09.11.2018 03:13- Так у каждого фрагмента свой toolbar в xml файле прописываешь. Я обычно делаю общее только DrawerLayout или BottomNavigationBar. Ну и естественно всякие алерты вроде «Нет подключения к интернету» 
 
  - egordeev08.11.2018 20:59- вроде фрагменты были придуманы как workaround?  - XIII-th Автор09.11.2018 15:58- Думаю, это не так. В графе навигации вместе неплохо уживаются и фрагменты и Activity. Более того, документация заявляет, что можно без особого труда реализовать свой узел навигации, хотя описано довольно скудно. 
 
 
 
           
 
barbanel
Отдельное спасибо за КДПВ, порадовали =)
XIII-th Автор
Рад, что удалось отразить основную мысль )