Hazard
Hazard

Reputation: 41

Application crash when navigating to fragment

I am using 3 fragments with 1 activity for user profile features. I use navigation to move to fragments: Nav Graph

The problem is when I go from profileFragment to editProfileFragment, change user's data and then go back to profileFragment by navigation action, I cannot reach editProfileFragment again from profileFragment. I got this error:

Navigation action/destination xxx:id/action_profileFragment_to_editProfileFragment cannot be found from the current destination Destination(xxx:id/editProfileFragment)

I am trying to use MVVM architecture so my navigation goes like this - in fragment I observe LiveData:

navController = Navigation.findNavController(view)
        viewModel.navigateTo.observe(viewLifecycleOwner, EventObserver {
            navController.navigate(it)
        })

viewModel 'navigateTo':

private val _navigateTo = MutableLiveData<Event<Int>>()
    val navigateTo: LiveData<Event<Int>> = _navigateTo

and the navigation methods:

fun goBackToProfile(){
        _navigateTo.value = Event(R.id.action_editProfileFragment_to_profileFragment)
    }

fun editProfileButtonClick() {
        _navigateTo.value = Event(R.id.action_profileFragment_to_editProfileFragment)
    }

I also use Event wrapper class by Jose Alcerreca:

open class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set // Allow external read but not write

    /**
     * Returns the content and prevents its use again.
     */

    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }

    /**
     * Returns the content, even if it's already been handled.
     */
    fun peekContent(): T = content
}

class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let {
            onEventUnhandledContent(it)
        }
    }
}

I don't know if error occurs because of Event wrapper or I do something wrong with navigation. I will appreciate any advices.

EDIT: 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/main_nav_graph"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="xxx.mainPackage.views.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" />
    <fragment
        android:id="@+id/profileFragment"
        android:name="xxx.mainPackage.views.ProfileFragment"
        android:label="fragment_profile"
        tools:layout="@layout/fragment_profile" >
        <action
            android:id="@+id/action_profileFragment_to_editProfileFragment"
            app:destination="@id/editProfileFragment" />
    </fragment>
    <fragment
        android:id="@+id/editProfileFragment"
        android:name="xxx.mainPackage.views.EditProfileFragment"
        android:label="fragment_edit_profile"
        tools:layout="@layout/fragment_edit_profile" >
        <action
            android:id="@+id/action_editProfileFragment_to_chooseImageFragment"
            app:destination="@id/chooseImageFragment" />
        <action
            android:id="@+id/action_editProfileFragment_to_profileFragment"
            app:destination="@id/profileFragment" />
    </fragment>
    <fragment
        android:id="@+id/chooseImageFragment"
        android:name="xxx.mainPackage.views.ChooseImageFragment"
        android:label="ChooseImageFragment" >
        <action
            android:id="@+id/action_chooseImageFragment_to_editProfileFragment"
            app:destination="@id/editProfileFragment" />
    </fragment>
</navigation>

Upvotes: 0

Views: 2825

Answers (2)

mightyWOZ
mightyWOZ

Reputation: 8315

Error is very clear, there is no action_profileFragment_to_editProfileFragment defined on editProfileFragment. if you look at your navigation xml, you can see that action_profileFragment_to_editProfileFragment is defined for ProfileFragment.

But you are trying to use this navigation action from EditProfileFragment, which causes the error. so either update your navigation to include this action for EditProfileFragment or use some action which is already defined for EditProfileFragment.

Upvotes: 1

Dương Minh
Dương Minh

Reputation: 2421

It looks to me like you're navigating the wrong way.

Firstly

You are moving from ProfileFragment to EditProfileFragment. Then you move from EditProfileFragment to ProfileFragment via action whose id is R.id.action_profileFragment_to_editProfileFragment.

That action I see you define from Fragment ProfileFragment, not EditFragment.

Make sure your LiveData navigateTo in EditProfileFragment trigger id is R.id.action_editProfileFragment_to_profileFragment when you want to open ProfileFragment from EditProfileFragment.

Secondly

When you return from EditProfileFragment , don't call navController.navigate() as it will keep your current fragment in the backstack and push your target fragment to the backstack. If you want to go back without keeping your current fragment in the backstack, call navController.popBackStack().

Upvotes: 1

Related Questions