4

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?

2
  • You can't grab FirstFragment's arguments from SecondFragment. FirstFragmentArgs is only available to be retrieved in FirstFragment. What is your intended functionality with this code? I can provide you with some suggestions for your implementation if you need. Commented Dec 16, 2019 at 6:01
  • I want to pass arguments from one fragment to second fragment as I did as bundle in FirstFragment. Instead of bundles I want to send arguments using navigation_graph as I have mentioned in code. As I did in SecondFragment I want to retrieve arguments which are send using navigation graph Commented Dec 16, 2019 at 6:14

2 Answers 2

2

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"
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your suggestion. While getting values I am not directly getting using arguments.clickFrom I need to do like this: val clickFromFragment = SecondFragmentArgs.fromBundle(arguments!!).clickFrom
0

If anyone is trying to use navigation arguments in Java this is how you retrieve arguments in SecondFragment

boolean isFirstFragment = SecondFragmentArgs.fromBundle(getArguments()).getIsFirstFragment();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.