Challenge 2: Pass an Argument with SafeArgs — Solution // app/build.gradle.kts (or the project-level build.gradle.kts, depending // on Gradle version) — add the SafeArgs plugin plugins { id("androidx.navigation.safeargs.kotlin") } // res/navigation/nav_graph.xml — declare the argument on detailsFragment // WelcomeFragment.kt — sending, via the generated Directions class binding.viewDetailsButton.setOnClickListener { val action = WelcomeFragmentDirections.actionWelcomeToDetails(message = "Hello from Welcome!") findNavController().navigate(action) } // DetailsFragment.kt — receiving, via the generated Args class class DetailsFragment : Fragment() { private lateinit var binding: FragmentDetailsBinding private val args: DetailsFragmentArgs by navArgs() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { binding = FragmentDetailsBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.detailText.text = args.message } } Notes: - WelcomeFragmentDirections.actionWelcomeToDetails(...) and DetailsFragmentArgs are BOTH generated automatically by the SafeArgs plugin from the nav graph's declaration — neither class is hand-written. - The parameter name (message) is checked by the compiler at the call site — passing the wrong type, or forgetting a required argument entirely, is a compile error, not a runtime crash the way a mistyped Intent extra key would be (Chapter 4). - val args: DetailsFragmentArgs by navArgs() uses Kotlin's property delegation (Kotlin Intermediate Chapter 4) — navArgs() is itself a delegate that reads the Fragment's arguments Bundle and exposes it as a typed args object.