Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Navigation component arguments default value

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?

like image 642
Nik Avatar asked Oct 29 '25 02:10

Nik


1 Answers

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"
    }
}
like image 108
Christilyn Arjona Avatar answered Oct 30 '25 17:10

Christilyn Arjona



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!