Navigation Architecture Component - DestinationFragmentArgs is not generated - android

I have this in app gradle:
apply plugin: 'androidx.navigation.safeargs'
implementation 'android.arch.navigation:navigation-fragment-ktx:1.0.0'
implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0'
and this in the project gradle:
classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0'
the navigation graph:
<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/loginPhoneNumberFragment">
<fragment
android:id="#+id/loginPhoneNumberFragment"
android:name="...fragments.LoginPhoneNumberFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_phone_number">
<action
android:id="#+id/action_loginPhoneNumberFragment_to_loginCodeFragment"
app:destination="#id/loginCodeFragment">
<argument
android:name="prefix"
app:argType="string" />
<argument
android:name="phone_number"
app:argType="string" />
</action>
</fragment>
<fragment
android:id="#+id/loginCodeFragment"
android:name="...LoginCodeFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_code" />
</navigation>
LoginPhoneNumberFragment:
val action = LoginPhoneNumberFragmentDirections.actionLoginPhoneNumberFragmentToLoginCodeFragment(prefix, phoneNumber)
view?.findNavController()?.navigate(action)
LoginCodeFragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val prefix = LoginCodeFragmentArgs.fromBundle(arguments).prefix //LoginCodeFragmentArgs is not recognized
}
In the LoginPhoneNumberFragment it creates the "LoginPhoneNumberFragmentDirections" class, but on the destination class, LoginCodeFragment, it doesn't recognize "LoginCodeFragmentArgs".
Can someone please tell me what am I missing?
(I cleaned and rebuilded, and tried Invalidate caches...)

Ok, so after a lot of searching I found out my mistake -
the arguments should be on the Destination fragment, and not on the starting one:
<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/loginPhoneNumberFragment">
<fragment
android:id="#+id/loginPhoneNumberFragment"
android:name="...fragments.LoginPhoneNumberFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_phone_number">
<action
android:id="#+id/action_loginPhoneNumberFragment_to_loginCodeFragment"
app:destination="#id/loginCodeFragment">
</action>
</fragment>
<fragment
android:id="#+id/loginCodeFragment"
android:name="...fragments.LoginCodeFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_code" >
<argument
android:name="prefix"
app:argType="string"
android:defaultValue="888" />
<argument
android:name="phone_number"
app:argType="string"
android:defaultValue="88888888"/>
</fragment>
</navigation>
You can also add it manually via the navigation graph design - press on the destination fragment and press "+" on the arguments section, it will add it to the text file.

The argument should be in the destination fragment as follows instead of inside the action in source fragment
<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/loginPhoneNumberFragment">
<fragment
android:id="#+id/loginPhoneNumberFragment"
android:name="...fragments.LoginPhoneNumberFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_phone_number">
<action
android:id="#+id/action_loginPhoneNumberFragment_to_loginCodeFragment"
app:destination="#id/loginCodeFragment"/>
</fragment>
<fragment
android:id="#+id/loginCodeFragment"
android:name="...LoginCodeFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_code">
<argument
android:name="prefix"
app:argType="string" />
<argument
android:name="phone_number"
app:argType="string" />
</fragment>
</navigation>

Related

How to replace a fragment in jetpack navigation component?

val action = LoginFragmentDirections.actionLoginFragmentToHomeFragment(
User(
_binding.emailEt.editText?.text.toString(),
_binding.passwordEt.editText?.text.toString()
)
)
findNavController().navigate(action)
This is my Button press action
<?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/nav_graph"
app:startDestination="#id/loginFragment">
<fragment
android:id="#+id/loginFragment"
android:name="com.example.passion.ui.LoginFragment"
android:label="fragment_logins"
tools:layout="#layout/fragment_logins">
<action
android:id="#+id/action_loginFragment_to_homeFragment"
app:destination="#id/homeFragment" />
</fragment>
<fragment
android:id="#+id/homeFragment"
android:name="com.example.passion.ui.HomeFragment"
android:label="fragment_home"
tools:layout="#layout/fragment_home" >
<argument
android:name="user"
app:argType="com.example.passion.data.models.User"
app:nullable="true"
android:defaultValue="#null" />
</fragment>
</navigation>
This is my navigation graph
Everytime I press button. it adds the fragment. I want to replace it with HomeFragment
Any help would be appreciated!. thanks

Is there a way to update Jetpack Navigation Graph for a Fragment that can be accessible by any Fragment in the Graph?

Given I have a Jetpack Navigation Graph as below, where by
BlankFragment1 -> BlankFragment2 -> BlankFragment3 -> BlankFragment4 -> BlankFragment5
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="#id/blankFragment1">
<fragment
android:id="#+id/blankFragment1"
android:name="com.example.cashdog.cashdog.BlankFragment1"
android:label="#string/label_blank1"
tools:layout="#layout/fragment_blank1" >
<action
android:id="#+id/action_blankFragment1_to_blankFragment2"
app:destination="#id/blankFragment2" />
</fragment>
<fragment
android:id="#+id/blankFragment2"
android:name="com.example.cashdog.cashdog.BlankFragment2"
android:label="#string/label_blank2"
tools:layout="#layout/fragment_blank2" >
<action
android:id="#+id/action_blankFragment2_to_blankFragment3"
app:destination="#id/blankFragment3" />
</fragment>
<fragment
android:id="#+id/blankFragment3"
android:name="com.example.cashdog.cashdog.BlankFragment3"
android:label="#string/label_blank3"
tools:layout="#layout/fragment_blank3" >
<action
android:id="#+id/action_blankFragment3_to_blankFragment4"
app:destination="#id/blankFragment4" />
</fragment>
<fragment
android:id="#+id/blankFragment4"
android:name="com.example.cashdog.cashdog.BlankFragment4"
android:label="#string/label_blank4"
tools:layout="#layout/fragment_blank4" >
<action
android:id="#+id/action_blankFragment4_to_blankFragment5"
app:destination="#id/blankFragment5" />
</fragment>
<fragment
android:id="#+id/blankFragment5"
android:name="com.example.cashdog.cashdog.BlankFragment5"
android:label="#string/label_blank5"
tools:layout="#layout/fragment_blank5" />
</navigation>
If I have another Fragment, named FragmentSomething, that can be open by and of the FragmentBlank1 to FragentBlank5
Is there a way to update the NavGraph above for my FragmentSomething, without the need to add actions for all 5 of them?
Apparently, there's something called the global action
https://developer.android.com/guide/navigation/navigation-global-action
We just need to add this
<action android:id="#+id/action_global_somethingFragment"
app:destination="#id/somethingFragment"/>
<fragment
android:id="#+id/somethingFragment"
android:name="com.example.cashdog.cashdog.SomethingFragment"
android:label="#string/label_something"
tools:layout="#layout/fragment_something" />
Or we can navigate the code directly to somethingFragment using
findNavController().navigate(R.id.somethingFragment)

How to add a fragment from external library/framework?

I am trying to add a fragment which has implementation done as part of an external framework. Need to include/reference the fragment in the running application. How this can be done?
below is the navigation XML for reference.
<?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"
android:id="#+id/main"
app:startDestination="#id/officeFragment">
<fragment
android:id="#+id/officeFragment"
android:name="com.sample.office.OfficeFragment"
android:label="#string/office">
<argument
android:name="officeId"
app:argType="string"
app:nullable="false" />
<action
android:id="#+id/viewEmployees"
app:destination="#id/profileListFragment"/>
</fragment>
<fragment
android:id="#+id/profileListFragment"
android:name="com.externallibrary.component.people.ui.profilelist.ProfileListFragment"
android:label="#string/people">
<argument
android:name="officeId"
android:defaultValue="#null"
app:argType="string"
app:nullable="true" />
</fragment>
</navigation>

Navigating to other graph part in navigation components

I have the problem that my sample app crashes when I deeplink from one graph part to the other one.
My structure is simple:
Two tabs with own graphs which have each two possible fragments
When I navigate to a detail page (in my sample a book) this just works from my "Shelf" but not from the home screen.
Here is my full graph:
<?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/sample"
app:startDestination="#id/tab_home">
<navigation
android:id="#+id/tab_home"
app:startDestination="#id/frag_home">
<fragment
android:id="#+id/frag_home"
android:name="eu.rekisoft.android.navbug.HomeFragment"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/cause_bug"
app:destination="#id/frag_hint"/>
<action
android:id="#+id/causeCrash"
app:destination="#id/frag_book">
<argument
android:name="name"
app:argType="string"/>
</action>
</fragment>
<fragment
android:id="#+id/frag_hint"
android:name="eu.rekisoft.android.navbug.HintFragment"
android:label="Hint"
tools:layout="#layout/fragment_hint"/>
</navigation>
<navigation
android:id="#+id/tab_books"
app:startDestination="#id/frag_shelf">
<fragment
android:id="#+id/frag_shelf"
android:name="eu.rekisoft.android.navbug.ShelfFragment"
android:label="Shelf Fragment"
tools:layout="#layout/fragment_shelf">
<action
android:id="#+id/open_book"
app:destination="#id/frag_book">
<argument
android:name="name"
app:argType="string"/>
</action>
</fragment>
<fragment
android:id="#+id/frag_book"
android:name="eu.rekisoft.android.navbug.BookFragment"
android:label="Book Fragment"
tools:layout="#layout/fragment_book">
<argument
android:name="name"
app:argType="string"/>
</fragment>
</navigation>
</navigation>
Here is my crash:
java.lang.IllegalArgumentException: Navigation destination eu.rekisoft.android.navbug:id/frag_book referenced from action eu.rekisoft.android.navbug:id/causeCrash cannot be found from the current destination Destination(eu.rekisoft.android.navbug:id/frag_home) class=eu.rekisoft.android.navbug.HomeFragment
at androidx.navigation.NavController.navigate(NavController.kt:1527)
at androidx.navigation.NavController.navigate(NavController.kt:1464)
at androidx.navigation.NavController.navigate(NavController.kt:1922)
at eu.rekisoft.android.navbug.HomeFragment.onViewCreated$lambda-2$lambda-1(HomeFragment.kt:23)
at eu.rekisoft.android.navbug.HomeFragment.$r8$lambda$q53N5QXeJ-lbbpd7MjwkcKbt9_4(Unknown Source:0)
at eu.rekisoft.android.navbug.HomeFragment$$ExternalSyntheticLambda1.onClick(Unknown Source:2)
Very clear error message, but I don't know how to fix this.
If you want to checkout my code check this GitHub repo.

Android Navigation Components always returns to the start destination

I'm using the Navigation Component and I have 1 Activity with 3 fragments (startDestination: mainFragment , levelFragment and gameFragment). if I'm in levelFragment, it returns to mainFragment, and if I'm in gameFragment it should return to levelFragment, but it returns to mainFragment instead.
I followed the documentation in order to solve the problem but I didn't find any solutions and it's still happening, Why?
Note: gameFragment returns to levelFragment(it appears for just a split second) then immediately returns to mainFragment.
Here's my navigation.xml :
<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"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="com.hroub.physicsapp.MainFragment"
android:label="fragment_main"
tools:layout="#layout/fragment_main" >
<action
android:id="#+id/action_mainFragment_to_levelFragment"
app:destination="#id/levelFragment"
app:enterAnim="#android:anim/fade_in"
app:exitAnim="#android:anim/fade_out"
app:popEnterAnim="#android:anim/fade_in"
app:popExitAnim="#android:anim/fade_out" />
</fragment>
<fragment
android:id="#+id/gameFragment"
android:name="com.hroub.physicsapp.GameFragment"
android:label="fragment_game"
tools:layout="#layout/fragment_game" >
<argument
android:name="index"
app:argType="integer"
android:defaultValue="0" />
<argument
android:name="concept"
app:argType="com.hroub.physicsapp.model.Concept" />
<action
android:id="#+id/action_gameFragment_to_levelFragment"
app:destination="#id/levelFragment"
app:popUpTo="#id/levelFragment"
app:popUpToInclusive="true"
/>
</fragment>
<fragment
android:id="#+id/levelFragment"
android:name="com.hroub.physicsapp.LevelFragment"
android:label="fragment_level"
tools:layout="#layout/fragment_level" >
<action
android:id="#+id/action_levelFragment_to_gameFragment"
app:destination="#id/gameFragment"
app:enterAnim="#android:anim/fade_in"
app:exitAnim="#android:anim/fade_out"
app:popEnterAnim="#android:anim/fade_in"
app:popExitAnim="#android:anim/fade_out" />
<argument
android:name="position"
app:argType="integer"
android:defaultValue="0" />
</fragment>
Code to navigate to levelFragment :
MainFragmentDirections.ActionMainFragmentToLevelFragment action = MainFragmentDirections.actionMainFragmentToLevelFragment();
action.setPosition(getLayoutPosition());
Navigation.findNavController((Activity)context, R.id.main_host).navigate(action);
Code to navigate to gameFragment :
LevelFragmentDirections.ActionLevelFragmentToGameFragment action = LevelFragmentDirections.actionLevelFragmentToGameFragment(concept);
action.setIndex(getLayoutPosition());
action.setConcept(concept);
Navigation.findNavController((Activity)context, R.id.main_host).navigate(action);
from gameFragment to levelFragment :
Navigation.findNavController(requireActivity(), R.id.main_host).navigate(R.id.action_gameFragment_to_levelFragment);

Categories

Resources