В этой статье вы узнаете, кто такой этот Safe Args, как он упрощает жизнь и что является продуктом его работы, в том числе и за кулисами.
Вы сейчас во второй части большого материала про Navigation Component в многомодульном проекте. Если вы впервые слышите про Navigation Component, то рекомендую сначала почитать, что вообще такое Navigation Component. Если уже знакомы с азами, то можно переходить к самому интересному:
Safe Argsэто плагин, идущий отдельно от Navigation Component, но созданный специально для того, чтобы с библиотекой работалось легче. С ним нет необходимости указывать id destination-а и передавать параметры через Bundleплагин генерирует для этого отдельные классы и имеет набор extension-ов для работы с ними. Давайте разбираться, как это всё работает.
Во-первых, вместе с плагином появился новый тег в xml: <argument>. Он применим и к action, и к destinationтак можно передавать и принимать параметры в более удобном виде. Во-вторых, на основе экранов и переходов, указанных в графе, генерируются специальные классы, которые можно указывать в NavController-е вместо id action.
Show me thecode!
<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/graphuserflow app:startDestination=@id/fragmentUserList> <fragment android:id=@+id/fragmentUserList android:label=FragmentUserList android:name=com.example.usersList.UserListFragment tools:layout=@layout/fragmentuserlist> <action android:id=@+id/actiontouserdetails pp:destination=@id/fragmentUserList > <argument android:name=userId app:argType=integer app:nullable=false /> </action> </fragment> <fragment android:id=@+id/fragmentUserDetails android:label=FragmentUserDetails android:name=com.example.usersList.UserDetails tools:layout=@layout/fragmentuser_details/></navigation>
Здесь мы взяли: достаточно простой граф, где есть фрагмент, вложенный граф и переход от одного к другому. Единственная особенностьпресловутый <argument>, с помощью которого мы передаем в users details фрагмент параметр userId. Пересоберём проект и посмотрим, что получилось.
class UserListFragmentDirections private constructor() { private data class ActionUserFromListToDetails( val userId: Int ) : NavDirections { override fun getActionId(): Int = R.id.actionToUserDetails override fun getArguments(): Bundle { val result = Bundle() result.putInt(userId, this.userId) return result } } companion object { fun actionToUserDetails(userId: Int): NavDirections = ActionToUserDetails(userId) }}
В generated-папке модуля, где лежит граф, находим вот такой классобертку, которая включает в себя все переходы, указанные в графе с уже включенными туда параметрами. В нашем случае это переход на экран деталей пользователя и передача туда аргумента userId.
Теперь вызов перехода будет выглядеть так:
navController.navigate( UserListFragmentDirections.actionToUserDetails(userId))
А параметры в целевом destination-е можно получить через extension, который теперь у нас имеется.
private val args by navArgs<UserDetailsFragmentArgs>()private val userId by lazy { args.userId }
Сам класс аргументов тоже генерируется в отдельный класс, который содержит методы упаковки и распаковки параметров в Bundle, но он уже не так интересен.
В итоге
Safe Argsприятное дополнение к Navigation Component, благодаря которому мы облегчили себе работу с id переходов и обработки получения/отправки их аргументов. Использовать его или нетдело ваше, но дальнейшее повествование основано на использовании это плагина. Спойлер: он принесет немало проблем, но в конце все будут счастливы:)
А теперь к самому интересному. Взглянем, как можно организовать работу с Navigation Component в многомодульном проекте совместно с SafeArgs и iOS-like multistack-навигацию.