mafortis
mafortis

Reputation: 7138

Kotlin Navigation cannot find fragments

I have multiple navigation graphs for multiple activities but I always have problem with navigating to fragments by navController. It always return such errors cannot be found from the current destination Destination

java.lang.IllegalArgumentException: Navigation action/destination com.my.app:id/action_orderDetailFragment_to_driverMapFragment cannot be found from the current destination Destination(com.my.app:id/driverMapFragment) label=fragment_driver_map class=com.my.app.orders.DriverMapFragment

I've tried various amount of solutions from safeargs by using Directions also navigate by ids etc. they all end up with same error. It becomes frustrating to deal with navigations

navigation screenshot

one

Fragment

class OrderDetailFragment : Fragment(), View.OnClickListener {

    lateinit var navController: NavController
    lateinit var drivermap: Button

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        navController = Navigation.findNavController(view)
        view.findViewById<Button>(R.id.drivermap).setOnClickListener(this)
    }
    
    // other functions....

    // here suppose to redirect to "driverMapFragment" from "orderDetailFragment" along with "Order ID"
    override fun onClick(v: View?) {
        when(v!!.id) {
            R.id.drivermap -> {
                // (1) Returning Error
                val bundle = bundleOf("orderIDArgument" to orderIDArgument)
                navController!!.navigate(R.id.action_orderDetailFragment_to_driverMapFragment, bundle)

                // (2) Returning Error
                // val action = OrderDetailFragmentDirections.actionOrderDetailFragmentToDriverMapFragment(bundle)
                // v.findNavController().navigate(action)
            }
        }
    }
}

PS: To avoid unnecessary comments I have to mention that I do have safeargs in gradles.

app level gradle

apply plugin: "androidx.navigation.safeargs.kotlin"

project level gradle

dependencies {
  classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5"
}

Update 1

two

Update 2

Structure

  1. I have OrdersFragment where list of all orders are showing to user
  2. As I was facing very same issue about getting details fragment from that list items what I did was creating new activity named it OrdersActivity in this activity I get order details by OrderDetailFragment (main fragment of the activity)
  3. Now OrdersActivity has new fragment which I'm trying to show map of order (redirecting from OrderDetailFragment to driverMapFragment)

PS: I am aware that this structure is a bit messed up (mostly because I was forced to make OrdersActivity which I didn't want to, but same issue (error) made me to do it this way.

Now here is my activity_orders.xml

<ScrollView
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="56dp"
    android:fillViewport="true"
    tools:context=".orders.OrdersActivity">

        // by default it loads `OrderDetailFragment` then its supposed to switch to maps fragment when button is clicked inside `OrderDetailFragment`    
        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/orderFragmentId"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/order_detail" />
</ScrollView>

OrdersActivity.kt

class OrdersActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_orders)

        // make sure main fragment loads only once
        if (savedInstanceState == null) {
            supportFragmentManager
                .beginTransaction()
                .add(R.id.orderFragmentId, OrderDetailFragment())
                .commit()
        }
    }

    private fun navigateTo(fragment: Fragment) {
        val transaction = supportFragmentManager
            .beginTransaction()
            .replace(R.id.orderFragmentId, fragment)
        transaction.commit()
    }
}

Upvotes: 1

Views: 1049

Answers (3)

soggypants
soggypants

Reputation: 425

I put <argument> element as child of <fragment> and not as child of <action>. Immediately I got to use ClassNameArgs by navArgs().

<fragment
    android:id="@+id/SecondFragment"
    android:name="com.example.easybrowsing.SecondFragment"
    android:label="@string/second_fragment_label"
    tools:layout="@layout/fragment_second">

    <action
        android:id="@+id/action_SecondFragment_to_FirstFragment"
        app:destination="@id/FirstFragment" />
    <argument
        android:name="website"
        app:argType="com.example.easybrowsing.Website" />
</fragment>

Upvotes: 0

ianhanniballake
ianhanniballake

Reputation: 200100

You are using NavHostFragment, you should not be using any FragmentTransaction at all - you're adding a second instance of your OrderDetailFragment that is outside of the NavHostFragment.

Remove all of that code from your OrdersActivity:

class OrdersActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_orders)
    }
}

Upvotes: 1

EpicPandaForce
EpicPandaForce

Reputation: 81578

You need to move the <action outside of the <fragment, it should be a child of <navigation tag.

Upvotes: 0

Related Questions