В этом уроке рассмотрим как передавать данные при навигации.
Полный список уроков курса:
- Урок 1. Lifecycle
- Урок 2. LiveData
- Урок 3. LiveData. Дополнительные возможности
- Урок 4. ViewModel
- Урок 5. Room. Основы
- Урок 6. Room. Entity
- Урок 7. Room. Insert, Update, Delete, Transaction
- Урок 8. Room. Query
- Урок 9. Room. RxJava
- Урок 10. Room. Запрос из нескольких таблиц. Relation
- Урок 11. Room. Type converter
- Урок 12. Room. Миграция версий базы данных
- Урок 13. Room. Тестирование
- Урок 14. Paging Library. Основы
- Урок 15. Paging Library. PagedList и DataSource. Placeholders.
- Урок 16. Paging Library. LivePagedListBuilder. BoundaryCallback.
- Урок 17. Paging Library. Виды DataSource
- Урок 18. Android Data Binding. Основы
- Урок 19. Android Data Binding. Код в layout. Доступ к View
- Урок 20. Android Data Binding. Обработка событий
- Урок 21. Android Data Binding. Observable поля. Двусторонний биндинг.
- Урок 22. Android Data Binding. Adapter. Conversion.
- Урок 23. Android Data Binding. Использование с include, ViewStub и RecyclerView.
- Урок 24. Navigation Architecture Component. Введение
- Урок 25. Navigation. Передача данных. Type-safe аргументы.
- Урок 26. Navigation. Параметры навигации
- Урок 27. Navigation. NavigationUI.
- Урок 28. Navigation. Вложенный граф. Global Action. Deep Link.
- Урок 29. WorkManager. Введение
- Урок 30. WorkManager. Критерии запуска задачи.
- Урок 31. WorkManager. Последовательность выполнения задач.
- Урок 32. WorkManager. Передача и получение данных
- Урок 33. Практика. О чем это будет.
- Урок 34. Практика. TodoApp. Список задач.
- Урок 35. Практика. TodoApp. Просмотр задачи
Чтобы при вызове destination передать данные, необходимо использовать Bundle. Для него оставили местечко в методе navigate
Bundle bundle = new Bundle(); bundle.putString("arg1", "value1"); bundle.putInt("arg2", 2); navController.navigate(R.id.fragment2, bundle);
Создаем Bundle, наполняем аргументами и передаем в метод navigate вместе с ID destination (или action).
В фрагменте fragment2 метод getArguments вернет следующий Bundle:
Bundle[{arg1=value1, arg2=2}]
Соответственно получить данные можно стандартным путем:
String arg1Value = getArguments().getString("arg1"); Integer arg2Value = getArguments().getInt("arg2");
А если вызывали не фрагмент, а Activity, то так:
String arg1Value = getIntent().getStringExtra("arg1"); Integer arg2Value = getIntent().getIntExtra("arg2", 0);
Аргументы в графе
В графе мы можем для destination добавить аргументы и прописать им значения по умолчанию.
Секция Arguments. Указываем имя аргумента, тип и значение по умолчанию. Тип может быть string, integer и reference.
Если тип reference, то мы можем указать идентификатор какого-либо ресурса. В данном примере я указал dimen и string ресурсы. Они имеют следующие значения.
<dimen name="some_size">20dp</dimen>
<string name="app_name">Navigation</string>
Давайте проверим, как работают эти значения по умолчанию. Снова вызовем fragment2 и при этом не будем задавать никаких значений для аргументов, которые только что создали.
Bundle bundle = new Bundle(); bundle.putString("arg1", "value1"); bundle.putInt("arg2", 2); navController.navigate(R.id.fragment2, bundle);
В результате getArguments в фрагменте выглядит так:
Bundle[{arg1=value1, arg2=2, arg3=defaultValue3, arg4=52, arg5=Navigation}]
Для аргументов arg3, arg4 и arg5 пришли дефолтные значения. Причем reference идентификаторы были конвертированы в соответствующие им значения. arg4 надо получать, как Int, а arg5 - как String.
Значения по умолчанию будут приходить, если мы в коде не поместили в Bundle какое-либо свое значение аргумента.
Если для аргумента нет значения по умолчанию в графе и в коде ничего не было задано в Bundle, то в destination этот аргумент просто не придет.
Type-safe
Студия может сгенерировать нам классы и методы для удобной передачи аргументов. Для этого нам понадобится safeargs плагин.
В build.gradle файл проекта в секцию buildscript > dependencies необходимо добавить classpath
buildscript { repositories { google() } dependencies { classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha01" } }
А в build.gradle модуля добавляем плагин safeargs
apply plugin: 'com.android.application' apply plugin: 'androidx.navigation.safeargs' android { //... }
Для полноценного использования плагина необходимо использовать action.
Добавим action, который будет вести из fragment1 к fragment2 и укажем ID = actionToFragment2.
Обратите внимание, что action подтянул аргументы из destination в который он ведет, т.е. из fragment2. И мы можем указать для них значения по умолчанию.
Итак, у нас в графе есть три компонента, которые участвуют в навигации:
- destination, которому принадлежит (из которого выходит) action (ID = fragment1)
- action (ID = actionToFrgament2)
- destination, в который ведет action (ID = fragment2)
Для каждого из них будет сгенерирован свой класс. Если классы не генерируются, нажмите Ctrl+F9.
Отправитель
Для fragment1 будет сгенерирован класс Fragment1Directions. Т.е. в качестве имени взято ID и добавлено слово Directions. В этом классе будет метод actionToFragment2(), который даст нам action ActionToFragment2.
action
ActionToFragment2 - сгенерированный класс для action actionToFragment2. У этого класса есть методы, соответствующие аргументам этого action (см. скриншот выше). Т.е. для аргументов arg3, arg4 и arg5 будут созданы методы:
setArg3(String arg3) setArg4(int arg4) setArg5(int arg5)
и мы сможем их использовать, чтобы задавать значения аргументов. Под капотом там все также используется Bundle.
Код навигации будет выглядеть так:
Fragment1Directions.ActionToFragment2 action = Fragment1Directions.actionToFragment2(); action.setArg3("value3").setArg4(R.dimen.some_other_size).setArg5(R.string.hello_blank_fragment); navController.navigate(action);
Получаем ActionToFragment2 из Fragment1Directions, задаем значения аргументов и передаем этот action в метод navigate.
Получатель
Для получателя будет сгенерирован класс Fragment2Args. Т.е. для имени используется ID destination + суффикс Args.
У этого класса будут созданы методы для извлечения данных из bundle.
Статический метод, для создания Fragment2Args с передачей ему bundle.
public static Fragment2Args fromBundle(Bundle bundle)
И методы получения значения аргументов.
public String getArg3() public int getArg4() public int getArg5()
Код извлечения аргументов будет выглядеть так:
Fragment2Args fragment2Args = Fragment2Args.fromBundle(getArguments()) String arg3Value = fragment2Args.getArg3(); Integer arg4Value = fragment2Args.getArg4(); Integer arg5Value = fragment2Args.getArg5();
А если получатель - Activity, то код такой:
String arg3Value = SecondActivityArgs.fromBundle(getIntent().getExtras()).getArg3();
Эти сгенерированные классы очень просты, вы всегда можете открыть их и посмотреть код. В целом они являются оберткой над Bundle.
Присоединяйтесь к нам в Telegram:
- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня