Problem with passing arguments to nested graph using navigation component - android

I'm trying to pass a Parcelable argument to a nested graph, but the generated function takes 0 arguments.
I found this thread and I can't see the difference between what I have and what they have.
This is my XML, I removed code to show just the problem
logged_content_nav_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/logged_content_nav_graph"
app:startDestination="#id/chooseCategoryFragment">
<fragment
android:id="#+id/productDetailFragment"
android:name="com.vendyapp.vendy.features.loggedcontent.productdetail.ui.ProductDetailFragment"
android:label="fragment_product_detail"
tools:layout="#layout/fragment_product_detail" >
<action
android:id="#+id/action_productDetailFragment_to_loginAndRegisterFragment"
app:destination="#id/login_nav_graph" />
<argument
android:name="product"
app:argType="com.vendyapp.vendy.features.loggedcontent.home.Product" />
</fragment>
<include app:graph="#navigation/login_nav_graph"/>
login_nav_graph.xml (NESTED)
<?xml version="1.0" encoding="utf-8"?>
<navigation android:id="#+id/login_nav_graph"
app:startDestination="#id/loginAndRegisterFragment"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<fragment
android:id="#+id/loginAndRegisterFragment"
android:name="com.vendyapp.vendy.features.login.ui.LoginAndRegisterFragment"
android:label="fragment_login_and_register"
tools:layout="#layout/fragment_login_and_register">
<argument
android:name="product"
app:argType="com.vendyapp.vendy.features.loggedcontent.home.Product"
app:nullable="true" />
<action
android:id="#+id/action_loginAndRegisterFragment_to_registerFragment"
app:destination="#id/registerFragment" />
<action
android:id="#+id/action_loginAndRegisterFragment_to_loginFragment"
app:destination="#id/loginFragment" />
</fragment>
</navigation>
With the nav graphs like this, in my Kotlin class I do
val action = ProductDetailFragmentDirections.actionProductDetailFragmentToLoginAndRegisterFragment(product)
findNavController().navigate(action)
But it says this function takes 0 arguments.
What am I getting wrong? Thanks in advance.

Related

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)

Navigated fragment shows behind the previous fragment in Navigation architecture component jetpack

<?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/restaurantListFragment">
<fragment
android:id="#+id/scanQRFragment"
android:name="com.example.dine.ui.view.home.scan_qr.ScanQRFragment"
android:label="fragment_scan_q_r"
tools:layout="#layout/fragment_scan_q_r" />
<fragment
android:id="#+id/restaurantListFragment"
android:name="com.example.dine.ui.view.home.restaurants.RestaurantListFragment"
android:label="fragment_restaurant_list"
tools:layout="#layout/fragment_restaurant_list" >
<action
android:id="#+id/action_restaurantListFragment_to_restaruntDetailFragment"
app:destination="#id/restaruntDetailFragment"
app:popUpTo="#id/restaurantListFragment" />
</fragment>
<fragment
android:id="#+id/myPlateFragment"
android:name="com.example.dine.ui.view.home.my_plate.MyPlateFragment"
android:label="fragment_my_plate"
tools:layout="#layout/fragment_my_plate" />
<fragment
android:id="#+id/accountFragment"
android:name="com.example.dine.ui.view.home.account.AccountFragment"
android:label="fragment_account"
tools:layout="#layout/fragment_account" />
<fragment
android:id="#+id/restaruntDetailFragment"
android:name="com.example.dine.ui.view.restaurant_detail.RestaruntDetailFragment"
android:label="RestaruntDetailFragment"
tools:layout="#layout/fragment_restarunt_detail" />
</navigation>
Here is the navigation graph file I have used for this navigation fragments.
private fun onItemSelected() {
findNavController().navigate(R.id.action_restaurantListFragment_to_restaruntDetailFragment)
}
I called the `onItemSelected() method on a action, any help would be great. thanks
While Navigating from Restaurant list to RestaurantDetail fragment It comes like this. I have been suffering from this issue so long

Navigate from one activity to another with Navigation Component

I am trying to navigate from one navigation graph (with the host fragment on the LoginActivity) to another navigation graph (with the host fragment on the HomeActivity). I know Google is advocating for single activity applications and thus I am only going to be using these two Activities (to keep it minimal).
My login_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/mobile_navigation"
app:startDestination="#id/nav_login">
<fragment
android:id="#+id/nav_login"
android:name="your.appname.LoginFragment"
android:label="#string/login_menu"
tools:layout="#layout/fragment_login" >
<action
android:id="#+id/action_nav_login_to_enterCellphone"
app:destination="#id/login_enter_cellphone"
app:popUpTo="#id/nav_login" />
</fragment>
<fragment
android:id="#+id/login_enter_cellphone"
android:name="your.appname.LoginEnterCellphoneFragment"
android:label="#string/enter_cellphone_fragment_label"
tools:layout="#layout/fragment_login_enter_cellphone" >
<action
android:id="#+id/action_enter_cellphone_to_enterOTPFragment"
app:destination="#id/enterOTPFragment"
app:popUpTo="#id/login_enter_cellphone" />
</fragment>
<fragment
android:id="#+id/enterOTPFragment"
android:name="your.appname.EnterOTPFragment"
android:label="#string/enter_otp_label"
tools:layout="#layout/fragment_enter_o_t_p" >
<action
android:id="#+id/action_enterOTPFragment_to_main_navigation"
app:destination="#id/main_navigation"
app:launchSingleTop="false" />
</fragment>
<include app:graph="#navigation/main_navigation" />
</navigation>
And main_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_navigation"
app:startDestination="#id/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="your.appname.HomeFragment"
android:label="Home"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/nav_profile"
android:name="your.appname.ProfileFragment"
android:label="#string/profile_menu"
tools:layout="#layout/fragment_profile" />
</navigation>
I found this answer and implemented it as follows
private fun navigateToHomeActivity() {
val action = EnterOTPFragmentDirections.actionEnterOTPFragmentToMainNavigation()
findNavController().navigate(action)
(activity as LoginActivity).finish() <-- later commented out
}
but it gives me the following error E/InputMethodManager: prepareNavigationBarInfo() rootView is null
If I comment out the above line the error goes away but it only replaces the current fragment with the HomeFragment.
How do I navigate to another Activity so that the source Activity is removed (Can't navigate back to it) and the Destination Activity is used?
You can define 2 navigation graphs:
ActivityA with navigation Graph A
ActivityB with navigation Graph B
In the GraphA you can define a destination to start ActivityB
<!-- Graph A -->
<navigation
....
<activity
android:id="#+id/activityB"
android:name=".ActivityB"
...>
<argument
.... />
</activity>
</navigation>
Then you can navigate to that activity ( = startActivity(intent)) using it like a destination:
Navigation.findNavController(view).navigate(R.id.activityB);
More info here.

Android Navigation Component - external included graph receiving one argument

I am using the navigation component from Jetpack.
My main graph is huge, so I have decided to split it into different graphs and use the <include /> functionality.
Problem is that some of the included graphs receive arguments, but Android seems to ignore the arguments when creating the navigation Directions
Ie:
Main Graph (simplified)
<?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">
<fragment
android:id="#+id/listFragment"
android:name="com......ListFragment">
<action
android:id="#+id/view_detail"
app:destination="#id/item_detail"/>
</fragment>
<include app:graph="#navigation/included_graph"/>
</navigation>
Included graph: (simplified)
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/item_detail"
app:startDestination="#id/itemDetailFragment">
<argument
android:name="item_id"
app:argType="integer" />
<fragment
android:id="#+id/itemDetailFragment"
android:name="com......ItemDetailFragment">
<argument
android:name="item_id"
app:argType="integer" />
</fragment>
[...]
</navigation>
The class generated by android is
class ListFragmentDirections private constructor() {
companion object {
fun viewDetail(): NavDirections =
ActionOnlyNavDirections(R.id.view_detail)
}
}
It seems the argument received by the included graph is ignored - I can't pass any argument safely.
Is there are workaround for this?
I'm interested in any alternative letting me breaking down the graph into smaller files, based on <include /> or not.
There is a workaround: include the argument to the action explicitly, i.e.
<?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">
<fragment
android:id="#+id/listFragment"
android:name="com......ListFragment">
<action
android:id="#+id/view_detail"
app:destination="#id/item_detail">
<argument
android:name="item_id"
app:argType="integer" />
</action>
</fragment>
<include app:graph="#navigation/included_graph"/>
</navigation>

Is it possible to have dynamic destination in Nested Navigation Graph Android?

I have implemented a nested graph in Navigation graph, which is having 2 graphs. In the first graph, there are 3 fragments and in the second graph, there are 2 fragments. Graph 2 is included in graph 1. I want to navigate to (graph 1 step 1) to (graph 2 step 2). We can not define action between two nested fragments. So is there any way by which we can assign the dynamic destination to navigation?
Graph 1
<?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/mobile_navigation"
app:startDestination="#id/dashboardFragment">
<fragment
android:id="#+id/dashboardFragment"
android:name="com.navigationgraphexample.fragments.DashboardFragment"
android:label="fragment_dashboard"
tools:layout="#layout/fragment_dashboard" >
<action
android:id="#+id/action_dashboardFragment_to_stepOneFragment2"
app:destination="#id/stepOneFragment" />
<action
android:id="#+id/action_dashboardFragment_to_sub_nav"
app:destination="#id/sub_nav" />
</fragment>
<fragment
android:id="#+id/stepOneFragment"
android:name="com.navigationgraphexample.fragments.StepOneFragment"
android:label="fragment_step_one"
tools:layout="#layout/fragment_step_one">
<action
android:id="#+id/action_stepOneFragment_to_stepTwoFragment"
app:destination="#id/stepTwoFragment" />
</fragment>
<fragment
android:id="#+id/stepTwoFragment"
android:name="com.navigationgraphexample.fragments.StepTwoFragment"
android:label="fragment_step_two"
tools:layout="#layout/fragment_step_two" />
<fragment
android:id="#+id/notificationFragment"
android:name="com.navigationgraphexample.fragments.NotificationFragment"
android:label="fragment_notification"
tools:layout="#layout/fragment_notification" >
<deepLink
android:id="#+id/deepLink"
app:uri="myapp.com/{myargs}"
/>
<argument android:name="myargs"
app:argType="integer"
android:defaultValue="1" />
</fragment>
<include app:graph="#navigation/sub_nav" />
</navigation>
Graph 2
<?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/sub_nav"
app:startDestination="#id/createNewTaskFragment">
<fragment
android:id="#+id/listFragment"
android:name="com.navigationgraphexample.fragments.ListFragment"
android:label="fragment_list"
tools:layout="#layout/fragment_list" />
<fragment
android:id="#+id/createNewTaskFragment"
android:name="com.navigationgraphexample.fragments.CreateNewTaskFragment"
android:label="fragment_create_new_task"
tools:layout="#layout/fragment_create_new_task" >
<action
android:id="#+id/action_createNewTaskFragment_to_listFragment"
app:destination="#id/listFragment" />
</fragment>
</navigation>
I have checked this solution but it is not for the nested graph!
As far as class NavGraph extends NavDestination, you can try the following to change nested graph's startDestination before calling navigate to sub_nav:
val graph = navController.graph.findNode(R.id.sub_nav)
if (graph is NavGraph) {
graph.startDestination = R.id.createNewTaskFragment
}
UPD: Since version 2.4.0 all Navigation artifacts have been rewritten in Kotlin, so the setter should be accessed by it's original name:
graph.setStartDestination(R.id.createNewTaskFragment)

Categories

Resources