Search code examples
androidandroid-architecture-componentsandroid-jetpackandroid-navigation

Passing Multiple Agument to fragment using TypeSafe in Navigation


I know it is possible to pass a single argument using Action in the source fragment

  override fun onClick(v: View) {
       val amountTv: EditText = view!!.findViewById(R.id.editTextAmount)
       val amount = amountTv.text.toString().toInt()
       val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
       v.findNavController().navigate(action)

}

and get that in the destination fragment as specified in android docs

    val args: ConfirmationFragmentArgs by navArgs()
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            val tv: TextView = view.findViewById(R.id.textViewAmount)
            val amount = args.amount
            tv.text = amount.toString()
}

please let me know is there any way to pass multiple arguments in TypeSafe way


Solution

  • Yes, you could do it by defining multiple arguments for your fragment in the Navigation graph and then pass them to the action in your code. This is an example:

    navigation.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"
        app:startDestination="@id/firstFragment">
        <fragment
            android:id="@+id/firstFragment"
            android:name="com.example.app.FirstFragment"
            android:label="FirstFragment"
            tools:layout="@layout/fragment_first">
            <action
                android:id="@+id/action_firstFragment_to_secondFragment"
                app:destination="@id/secondFragment"
                app:enterAnim="@anim/slide_in_right"
                app:popExitAnim="@anim/slide_out_left" />
        </fragment>
        <fragment
            android:id="@+id/secondFragment"
            android:name="com.example.app.SecondFragment"
            android:label="secondFragment"
            tools:layout="@layout/fragment_second">
            <argument
                android:name="firstDataList"
                app:argType="com.example.app.domain.FirstData[]" />
            <argument
                android:name="secondDataList"
                app:argType="com.example.app.domain.SecondData[]" />
    
            <argument
                android:name="isOkey"
                app:argType="boolean" />
            <argument
                android:name="myString"
                app:argType="string" />
        </fragment>
    
    
    </navigation>
    

    and then in your code:

    You should pass the arguments respectively as it is navigation.xml

    FirstFragment.kt

    findNavController().navigate(
        FirstFragmentDirections.actionFirstFragmentToSecondFragment(
            firstDataList.toTypedArray(),
            secondDataList.toTypedArray(),
            isOkey,
            myString
        )
    

    And then retrieve it at the destination as a bundle like so:

    SecondFragment.kt

    val args = arguments?.let {
        SecondFragmentArgs.fromBundle(
            it
        )
    }
    if (args != null) {
        firstDataList = args.firstDataList.toCollection(ArrayList())
        secondDataList = args.secondDataList.toCollection(ArrayList())
        isOkey = args.isOkey
        myString = args.myString
    
    }
    

    To pass complex objects you should make them parcelable. In my example, I passed two lists of complex models that I parcelized them like this:

    DataModels.kt

    @Parcelize
    data class FirstData(var id: Int, var color: Int = 0) : Parcelable
    
    @Parcelize
    data class SecondData(var name: String, var position: ArrayList<Int>) : Parcelable