Navigation. Вкладений граф. Global Action. Deep Link.

Вкладений граф - це граф, який може бути створений всередині іншого графа.

Для цього треба виділити весь destination, який ви хочете перемістити у вкладений граф, натиснути правою кнопкою і вибрати Move to Nested Graph > New Graph

Вкладений граф - це звичайний destination в основному графі. Так само, як фрагмент або Activity. І в цього destination є параметри. Усе тут нам уже знайоме.

Подвійним кліком можна відкрити граф

Повернутися назад в основний граф можна натиснувши на Root у лівій панелі:

Я не знайшов, як у дизайнері трансформувати вкладений граф назад у фрагменти в основному графі. Найпростіше це зробити руками через XML.

Так виглядає граф із вкладеним графом

<?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"
   app:startDestination="@id/fragment1">
   <fragment
       android:id="@+id/fragment1"
       android:name="ru.startandroid.navigation.Fragment1"
       android:label="@string/fragment_1_title"
       tools:layout="@layout/fragment1" />
   <navigation
       android:id="@+id/navigation2"
       app:startDestination="@id/fragment2">
       <fragment
           android:id="@+id/fragment2"
           android:name="ru.startandroid.navigation.Fragment2"
           android:label="@string/fragment_2_title"
           tools:layout="@layout/fragment2" />
       <fragment
           android:id="@+id/fragment3"
           android:name="ru.startandroid.navigation.Fragment3"
           android:label="@string/fragment_3_title"
           tools:layout="@layout/fragment3" />
   </navigation>
</navigation>

Тобто вкладений граф - це тег navigation всередині основного 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"
   app:startDestination="@id/fragment1">
   <fragment
       android:id="@+id/fragment1"
       android:name="ru.startandroid.navigation.Fragment1"
       android:label="@string/fragment_1_title"
       tools:layout="@layout/fragment1"/>
 
 
 
       <fragment
           android:id="@+id/fragment2"
           android:name="ru.startandroid.navigation.Fragment2"
           android:label="@string/fragment_2_title"
           tools:layout="@layout/fragment2" />
       <fragment
           android:id="@+id/fragment3"
           android:name="ru.startandroid.navigation.Fragment3"
           android:label="@string/fragment_3_title"
           tools:layout="@layout/fragment3" />
 
</navigation>

Навігація

Припустимо, ми створили вкладений граф із фрагментами fragment2 і fragment3. А в основному графі залишився fragment1.

Тепер, перебуваючи у fragment1 ми не можемо зробити так:

navController.navigate(R.id.fragment2);

Буде помилка: navigation destination ru.startandroid.navigation:id/fragment2 is unknown to this NavController.

Так відбувається, тому що fragment1 знаходиться в основній графі. І коли ми з fragment1 намагаємося кудись перейти, то контролер намагається знайти ціль (fragment2) у цьому ж графі, але там її немає. Зате там є вкладений граф з ID = navigation2. Ось його і треба відкривати:

navController.navigate(R.id.navigation2);

У результаті контролер знайде destination c ID = navigation2, побачить, що це граф, і відкриє його стартовий destination, тобто fragment2.

Тобто із зовнішнього графа не можна викликати destination вкладеного графа. А ось навпаки - можна.

Додамо, наприклад, fragment4

З будь-якого destination у вкладеному графі ми можемо перейти до fragment4 звичайним шляхом:

navController.navigate(R.id.fragment4);

У цьому разі контролер спочатку буде шукати мету (fragment4) у поточному графі (navigation2), а якщо не знайде, то продовжить пошуки в батьківському графі і там уже знайде.

Усередині вкладених графів також можна створювати вкладені графи.

Global Action

Зазвичай у Action є destination-джерело, звідки ця дія може бути викликана, і destination-призначення, куди ця дія веде. Але можна зробити global action, у якого немає джерела. І будь-який destination зможе викликати цей action. Це зручно, якщо один і той самий destination викликається з різних місць, але при цьому використовуються одні й ті самі параметри.

global action створюється так: Він має ті самі атрибути, що й звичайний action Викликається він теж, як звичайний action

navController.navigate(R.id.action_global_fragment3);

Deep Link призначений для відкриття програми відразу на певному екрані. За допомогою Navigation Component ми можемо присвоювати такі посилання необхідним destination.

Наприклад для fragment3, ми присвоїмо посилання: app://myapp/frag3 Далі, якщо у вас студія версії 3.2, то в маніфесті в тег Activity, необхідно додати тег nav-graph

<activity
   android:name=".MainActivity"
   android:label="MainActivity">
   
   ...
 
   <nav-graph android:value="@navigation/main_graph" />
</activity>

І студія сама налаштує Intent Filter.

Якщо ж у вас студія старішої версії, то необхідно вручну налаштувати Intent Filter під цей deep link.

Перевірити посилання можна за допомогою adb команди:

adb shell am start -a android.intent.action.VIEW -d "app://myapp/frag3"

При виклику цієї команди буде відкрито застосунок, а в ньому відразу fragment3.

У deep link посиланні можна використовувати параметри. Наприклад, якщо для фрагмента задано таке посилання:

app://myapp/frag3/{id}

то після виклику посилання

app://myapp/frag3/100

ми у фрагменті, що відкрився, можемо отримати id з аргументів.

String id = getArguments().getString("id");

Символ .* дає змогу замінити частину посилання

Тобто якщо посилання задано таким чином:

app://myapp/frag3/.*/{id}

то фрагмент буде відкрито при виклику посилання:

app://myapp/frag3/test1/100

або

app://myapp/frag3/test1/test2/100