In navigation component, While sending arguments from first fragment to second fragment, default values are not getting which set from navigation graph.
Here is my code:
navigation_graph.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"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/firstFragment">
    <fragment
        android:id="@+id/firstFragment"
        android:name="com.example.navigationcomponent.FirstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first" >
        <action
            android:id="@+id/action_firstFragment_to_secondFragment"
            app:destination="@id/secondFragment"
            app:enterAnim="@anim/nav_default_enter_anim" />
        <argument
            android:name="clickFrom"
            app:argType="string"
            android:defaultValue="From First Fragment" />
        <argument
            android:name="clickFragmentPosition"
            app:argType="integer"
            android:defaultValue="1" />
    </fragment>
    <fragment
        android:id="@+id/secondFragment"
        android:name="com.example.navigationcomponent.SecondFragment"
        android:label="fragment_second"
        tools:layout="@layout/fragment_second" />
</navigation>
FirstFragment:
class FirstFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_first, container, false)
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val bundle = Bundle()
        bundle.putBoolean("IsFirstFragment", true)
        val navController = Navigation.findNavController(activity!!, R.id.my_nav_host_fragment)
        btnNext.setOnClickListener {
            navController.navigate(R.id.action_firstFragment_to_secondFragment, bundle)
        }
    }
}
SecondFragment:
class SecondFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_second, container, false)
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val isFromFirstFragment = arguments?.getBoolean("IsFirstFragment", false)
        Log.d(TAG, "$isFromFirstFragment")
        Log.d(TAG, "${FirstFragmentArgs.fromBundle(arguments!!).clickFrom} ${FirstFragmentArgs.fromBundle(arguments!!).clickFragmentPosition}")
        val navController = Navigation.findNavController(activity!!, R.id.my_nav_host_fragment)
        btnBack.setOnClickListener {
            navController.navigateUp()
        }
        navController.addOnDestinationChangedListener { controller, destination, arguments ->
            Log.d("TAG", "${destination.label}");
        }
    }
    companion object {
        private const val TAG: String = "SecondFragment"
    }
}
Here while fetching default values in second fragment I am getting Null Pointer Exception
Log.d(TAG, "${FirstFragmentArgs.fromBundle(arguments!!).clickFrom} ${FirstFragmentArgs.fromBundle(arguments!!).clickFragmentPosition}")
My Question is, How can I get values of arguments set using navigation_graph.xml? Navigation Graph have auto-generated getter when you re-build the project. Is there any architecture to bind auto generated setters using default value?
If you want to send arguments from FirstFragment to SecondFragment, then you should replace your navigation_graph.xml with:
<?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/navigation_graph"
    app:startDestination="@id/firstFragment">
    <fragment
        android:id="@+id/firstFragment"
        android:name="com.example.navigationcomponent.FirstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first" >
        <action
            android:id="@+id/action_firstFragment_to_secondFragment"
            app:destination="@id/secondFragment"
            app:enterAnim="@anim/nav_default_enter_anim" />
    </fragment>
    <fragment
        android:id="@+id/secondFragment"
        android:name="com.example.navigationcomponent.SecondFragment"
        android:label="fragment_second"
        tools:layout="@layout/fragment_second">
        <argument
            android:name="clickFrom"
            app:argType="string"
            android:defaultValue="From First Fragment" />
        <argument
            android:name="clickFragmentPosition"
            app:argType="integer"
            android:defaultValue="1" />
        <argument
            android:name="isFirstFragment"
            app:argType="boolean"
            android:defaultValue="false" />
    </fragment>
</navigation>
Then, you can pass arguments from your FirstFragment like this:
class FirstFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_first, container, false)
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val navController = Navigation.findNavController(activity!!, R.id.my_nav_host_fragment)
        btnNext.setOnClickListener {
            navController.navigate(
                FirstFragmentDirections.actionFirstFragmentToSecondFragment( // this is an auto-generated class & method
                    // specify your arguments here: For example:
                    isFirstFragment = true,
                    clickFrom = "your argument here",
                    clickFragmentPosition = 1
                    // for default values, you can leave this blank
                )
            )
        }
    }
}
Then to retrieve arguments in SecondFragment
class SecondFragment : Fragment() {
    private val arguments: SecondFragmentArgs by navArgs() // add this line to retrieve arguments from navigation
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_second, container, false)
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val isFromFirstFragment = arguments.isFirstFragment
        Log.d(TAG, "$isFromFirstFragment")
        Log.d(TAG, "${arguments.clickFrom} ${arguments.clickFragmentPosition}")
        val navController = Navigation.findNavController(activity!!, R.id.my_nav_host_fragment)
        btnBack.setOnClickListener {
            navController.navigateUp()
        }
        navController.addOnDestinationChangedListener { controller, destination, arguments ->
            Log.d("TAG", "${destination.label}");
        }
    }
    companion object {
        private const val TAG: String = "SecondFragment"
    }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With