How to map NavArgs to NavArgument? - android

The issue I encountered is related to setting navigation graph programatically. What I want to achieve is to decide in Activity which fragment should be a start destination. What's more, each of these fragments have additional arguments.
Let's say we have such navigation 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/nav_graph">
<fragment
android:id="#+id/fragment1"
android:name="com.mypackage.Fragment1"
tools:layout="#layout/layout_fragment1">
<argument
android:name="argument1"
app:argType="int" />
</fragment>
<fragment
android:id="#+id/fragment2"
android:name="com.mypackage.Fragment2"
tools:layout="#layout/layout_fragment2">
<argument
android:name="argument2"
app:argType="string" />
</fragment>
</navigation>
If we use Safe Args plugin (androidx.navigation.safeargs.kotlin), two classes will be generated: Fragment1Args and Fragment2Args, both implementing NavArgs interface.
Now because we need to decide which fragment should became start destination, we need to make graph programatically:
val graph = navController.navInflater.inflate(R.navigation.nav_graph)
if (someCondition) {
graph.startDestination = R.id.fragment1
} else {
graph.startDestination = R.id.fragment2
}
navController.graph = graph
But Fragment1 and Fragment2 requires some additional arguments, so we need somehow to add them to graph. It turns out that graph has method addArguments(NavArguments), but as you see it's not NavArgs interface. Question is how to set these arguments properly that Fragment1 or Fragment2 will be able to extract?
I'm using 1.0.0-rc02 version of navigation framework.

When you add <argument> tag to your navigation XML, it is already creating the NavArgument classes when you call inflate(), so there's nothing you need to do to the graph in order to pass arguments to the start destination.
Instead, you should use setGraph(NavGraph, Bundle) to set the graph and pass initial arguments to the start destination.
// Construct your Bundle of arguments
val bundle = bundleOf()
// set the graph with specific arguments for the start destination
navController.setGraph(graph, bundle)

You said: "What I want to achieve is to decide in Activity which fragment should be a start destination."
And I think you're trying to make the decision in the fragmen, which is not correct here because you didn't open the fragment yet, Thus the correct behavior is to do that in activity e.g:
when (someCondition) {
TO_FRAGMENT_1-> {
findNavController(R.id.fragment).navigate(R.id.fragment1)
}
TO_FRAGMENT_2-> {
findNavController(R.id.fragment).navigate(R.id.fragment2)
}
}
And if the activity is the first activity in your app, you should use something else instead of args, e.g: SharedPref.

Related

Android Safe Args Navigation JetPack OnBackPress in Fragment

I chose the Safe Args method for passing data between fragments because of type-safty.
Sender fragment
btnNextPage.setOnClickListener{
val amountTv: EditText =
view!!.findViewById(R.id.edt_my_argument_view)
val amount = amountTv.text.toString()
val action =
NavFragment01Directions.actionNavFragment01ToNavFragment02(amount)
Navigation.findNavController(view).navigate(action)
}
Receiver fragment
private val args: NavFragment02Args by navArgs()
.
.
.
override fun onViewCreated(view: View, savedInstanceState:
Bundle?) {
super.onViewCreated(view, savedInstanceState)
val txtWhole: TextView = view.findViewById(R.id.txt_whole_02)
val receivedTxt = args.myArg
txtWhole.text = receivedTxt.toString()
}
My_nav
<?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/my_nav"
app:startDestination="#id/navFragment01">
<fragment
android:id="#+id/navFragment02"
android:name="alidoran.android.navigation_safe_args.NavFragment02"
android:label="fragment_nav02"
tools:layout="#layout/fragment_nav02" >
<argument
android:name="my_arg"
android:defaultValue="Ali"
app:nullable="true" />
</fragment>
<fragment
android:id="#+id/navFragment01"
android:name="alidoran.android.navigation_safe_args.NavFragment01"
android:label="fragment_nav01"
tools:layout="#layout/fragment_nav01" >
<action
android:id="#+id/action_navFragment01_to_navFragment02"
app:destination="#id/navFragment02" >
<argument
android:name="my_arg"
app:argType="string"
android:defaultValue="#null"
app:nullable="true" />
</action>
</fragment>
</navigation>
This is working perfectly.
Now I want to pass a value from the receiver fragment to the sender fragment after pressing the back button.
I know how to do it with Bundle but I want to do it by Safe Args.
Also, I know it is possible to create an action for it but I want to handle it in the back press corresponding to the below map.
As you see we need an action for attaching value(s) but I don't want to create an action from the second one to the first one. I know how to handle it in the back press but I want Safe Args way.
Using navigation component the best way is by savedStateHandle:
findNavController().previousBackStackEntry?.savedStateHandle?.set("key", result)
And observe the response with:
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Type>("key")?.observe(viewLifecycleOwner) {result ->
// the result.
}
As define in the doc:
To pass data back to Destination A from Destination B, first set up Destination A to listen for a result on its SavedStateHandle. To do so, retrieve the NavBackStackEntry by using the getCurrentBackStackEntry() API and then observe the LiveData provided by SavedStateHandle.
https://developer.android.com/guide/navigation/navigation-programmatic#returning_a_result
The most common way is to implement FragmentResultListener.
The documentation explain this well, possibly better than I could.
I implemented both methods. I had seen the #davidte suggested method on the internet, but my mistake was I had assumed that the result was back to the first Fragment immediately, so I had not tested it.
surprisingly, After implementation, it worked very well. The result is backed to the first method after backing to the first fragment.
The #Martin-Zeitler suggested method, disadvantages are
I didn't have type-safety
I have two key values in both fragments.
eventually, I have chosen #davidte method.

NavDeepLinkBuilder arguments bundle not received in destination fragment

I have 2 nav host activities Activity A and Activity B with each their own set of navigation graphs. I want to navigate from FragmentA which is in a nav graph hosted by Activity A to FragmentB which is in a nav graph hosted by Activity B to accomplish that i tried explicit deep linking. However no matter how I am not able to retrieve the argument in FragmentB its always the default value. I am using safe args. What am I doing wrong?
update: it seems the problem starts with a not accessible nav graph. Looking a bit more closely at the Log i realized that NavController logged the following message
Could not find destination com.myapp.app:id/nav_graph_b in the
navigation graph, ignoring the deep link from Intent....
the nav graph is hosted by the nav host activity B which is set in setComponentName. Why is the graph not accessible then?
the deeplink
val bundle = Bundle()
bundle.putInt("theIntKey", theInt)
val pendingIntent = NavDeepLinkBuilder(requireContext())
.setComponentName(NavHostActivityB::class.java)
.setGraph(R.navigation.nav_graph_b)
.setDestination(R.id.fragmentB)
.setArguments(bundle)
.createPendingIntent()
.send()
navgraph
<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_b"
app:startDestination="#id/fragmentC"
tools:ignore="UnusedNavigation">
<fragment
android:id="#+id/fragmentB"
android:name="FragmentB">
<argument
android:name="theIntKey"
app:argType="integer"
android:defaultValue="0" />
</fragment>
<!-- other fragments-->
</navigation>
inside FragmentB
//all of these three methods return always the default value
val theIntFromBundle = requireArguments().getInt("theIntKey")
private val args: FragmentBArgs by navArgs()
requireActivity().intent.extras?.let {
val args = FragmentBArgs.fromBundle(it)
}

Pass data back to previous fragment using Android Navigation

I've started using Android Architecture Components (Navigation and Safe Args, View Models) along with Koin library.
Currently, I've got a problem with passing arguments between two fragments - I need to pass a string value from fragment A to fragment B, modify this value in fragment B and pass it back to fragment A.
I've found one possible solution to my problem - shared view models. Unfortunately, this approach has one problem because I can pass and modify values between screens, but when the fragment A navigate to another destination the value in the shared view model is still stored and not cleared.
Is there any different solution of passing and modifying data between fragments in Android Navigation? I want to avoid clearing this one value by hand (when the fragment A is destroyed).
Android just released a solution for this; Passing data between Destinations (Navigation 2.3.0-alpha02), basically, in fragment A you observe changes in a variable and in fragment B you change that value before executing popBackStack().
Fragment A:
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe(viewLifecycleOwner) { result ->
// Do something with the result.
}
Fragment B:
navController.previousBackStackEntry?.savedStateHandle?.set("key", result)
navController.popBackStack()
You can use Fragment Result API.
Fragment A -> Fragment B
In Fragment A :
binding.buttonGo.setOnClickListener {
setFragmentResultListener(ADD_LOCATION) { key, bundle ->
clearFragmentResultListener(requestKey = ADD_LOCATION)
val selectedLocationModel =
bundle.getParcelable<LocationModel>(SELECTED_LOCATION_MODEL)
this.selectedLocationModel = selectedLocationModel
}
navToFragmentB()
}
In Fragment B:
setFragmentResult(
ADD_LOCATION,
bundleOf(SELECTED_LOCATION_MODEL to selectedLocationModel)
)
goBack()
Do not forget to call clearFragmentResultListener() before create new one.
Currently, I've got a problem with passing arguments between two fragments - I need to pass a string value from fragment A to fragment B, modify this value in fragment B and pass it back to fragment A.
The theoretical solution really is to have the two fragments in a shared <navigation tag, then scope the ViewModel to the ID of the navigation tag, this way you now share the ViewModel between the two screens.
To make this reliable, it's best to use the NavBackStackEntry of the Navigation tag as both a ViewModelStoreOwner and SavedStateRegistryOwner, and create an AbstractSavedStateViewModelFactory that will create the ViewModel using the ViewModelProvider, while also giving you a SavedStateHandle.
You can communicate the results from FragmentB to FragmentA using this SavedStateHandle, associated with the shared ViewModel (scoped to the shared NavGraph).
You can try this solution
<fragment
android:id="#+id/a"
android:name="...">
<argument
android:name="text"
app:argType="string" />
<action
android:id="#+id/navigate_to_b"
app:destination="#id/b" />
</fragment>
<fragment
android:id="#+id/b"
android:name="...">
<argument
android:name="text"
app:argType="string" />
<action
android:id="#+id/return_to_a_with_arguments"
app:destination="#id/a"
app:launchSingleTop="true"
app:popUpTo="#id/b"
app:popUpToInclusive="true" />
</fragment>
and navigation fragment
NavHostFragment.findNavController(this).navigate(BFragmentDirections.returnToAWithArguments(text))
ianhanniballake`s comment has helped me solve a similar problem
1) Pass string from Fragment A to Fragment B with action_A_to_B and SafeArgs.
2) popBackStack to remove Fragment B.
navController.popBackStack(R.id.AFragment, false);
or
navController.popBackStack();
3) Then pass modified data from B to A with action_B_to_A.
EDIT.
Here you have some another solution

Passing an argument between two fragments each of them in a different Navigation Graph

Using Android Navigation Component. I have two Navigation Graphs (each of them with their own flow), lets say navigation graphs A and B. I navigate successfully from A to B, but I can't manage to pass an argument from the last Fragment included in graph A to the start Fragment that belongs to graph B.
I am able to pass arguments between fragments that belong to the same graph, but the function to set the arguments is not been generated when navigating between to navigation graphs.
I am trying to accomplish that using safeargs.
Here is the navigation graphs code:
Navigation Graph A:
<navigation android:id="#+id/nav_graph_a"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="#id/fragment1">
<fragment
android:id="#+id/fragment1"
android:name="com.mypackage.fragments.Fragment1"
android:label="Fragment1">
<action
android:id="#+id/action_fragment1_to_fragment2"
app:destination="#id/fragment2"/>
</fragment>
<fragment
android:id="#+id/fragment2"
android:name="com.mypackage.fragments.Fragment2"
android:label="Fragment2">
<argument
android:name="thisArgumentAlwaysArrive"
android:defaultValue="null"
app:argType="string"/>
<action
android:id="#+id/action_fragment2_to_nav_graph_b"
app:destination="#id/nav_graph_b"/>
</fragment>
<include app:graph="#navigation/nav_graph_b"/>
Navigation Graph B:
<navigation android:id="#+id/nav_graph_b"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="#id/fragment3">
<fragment
android:id="#+id/fragment3"
android:name="com.mypackage.fragments.Fragment3"
android:label="Fragment3">
<argument
android:name="thisArgumentNeverArrive"
app:argType="string"/>
</fragment>
Any idea on how to accomplish this?
As stated in the documentation:
Note: Safe Args do not support cross-module navigation, as there is no direct action to the destination. In the previous example, although a Directions class would be generated for the target destination in settings, you aren't able to access the generated class from the classpath of the list module.
But you can use a bundle instead of nav_args like this:
From
FristFragmentDirections.actionFirstFragmentToSecondFragment(your_parameter).let { action ->
findNavController().navigate(action)
}
To
FristFragmentDirections.actionFirstFragmentToSecondFragment().let { action ->
findNavController().navigate(
action.actionId,
Bundle().apply { putString("parameter_key", your_parameter) }
)
}
Safe Args is the plugin for Gradle that creates the classes ClassArgs for the destinations.
The default controller provides a way to navigate to another NavGraph, in this case there is an implementation of a Navigator called NavGraphNavigator.
This navigator provides you with a navigate(NavGraph destination,Bundle args) function that passes the arguments to the start fragment.
So, the best way I have found to do what you are trying to achieve is to use the generated class to generate a bundle with the needed arguments.
var myBundle = YourFragmentIdInNavGraphArgs.Builder(var args..).toBundle()
and then use the default NavController to navigate to a navGraph destination like this.
view.findNavController().navigate(R.id.your_action_to_nav_graph_id,myBundle)
the implementation of the Navigator will take care of passing the arguments to the start fragment on the destination.
Hope it helps to some one.

How to change start destination of a navigation graph programmatically?

Basically, I have the following navigation graph:
I want to change my starting point in navigation graph to fragment 2 right after reaching it (in order to prevent going back to fragment 1 when pressing back button - like with the splash screen).
This is my code:
navGraph = navController.getGraph();
navGraph.setStartDestination(R.id.fragment2);
navController.setGraph(navGraph);
But, obviously it's not working and it gets back to fragment 1 after pressing back button.
Am I doing it wrong?
Is there any other solution?
UPDATE:
When you have nav graph like this:
<fragment
android:id="#+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment" />
</fragment>
<fragment
android:id="#+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
And you want to navigate to the second fragment and make it root of your graph, specify the next NavOptions:
NavOptions navOptions = new NavOptions.Builder()
.setPopUpTo(R.id.firstFragment, true)
.build();
And use them for the navigation:
Navigation.findNavController(view).navigate(R.id.action_firstFragment_to_secondFragment, bundle, navOptions);
setPopUpTo(int destinationId, boolean inclusive) - Pop up to a given destination before navigating. This pops all non-matching destinations from the back stack until this destination is found.
destinationId - The destination to pop up to, clearing all intervening destinations.
inclusive - true to also pop the given destination from the back stack.
ALTERNATIVE:
<fragment
android:id="#+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment"
app:popUpTo="#+id/firstFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="#+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
And then on your code:
findNavController(fragment).navigate(
FirstFragmentDirections.actionFirstFragmentToSecondFragment())
Old answer
Deprecated: The clearTask attribute for actions and the associated API in NavOptions has been deprecated.
Source: https://developer.android.com/jetpack/docs/release-notes
If you want to change your root fragment to fragment 2 (e.g. after pressing back button on fragment 2 you will exit the app), you should put the next attribute to your action or destination:
app:clearTask="true"
Practically it looks in a next way:
<fragment
android:id="#+id/firstFragment"
android:name="com.appname.package.FirstFragment"
android:label="fragment_first" >
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment"
app:clearTask="true" />
</fragment>
<fragment
android:id="#+id/secondFragment"
android:name="com.appname.package.SecondFragment"
android:label="fragment_second"/>
I've added app:clearTask="true" to action.
Now when you perform navigation from fragment 1 to fragment 2 use the next code:
Navigation.findNavController(view)
.navigate(R.id.action_firstFragment_to_secondFragment);
In MainActivity.kt
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.booking_navigation)
if (isTrue){
graph.startDestination = R.id.DetailsFragment
}else {
graph.startDestination = R.id.OtherDetailsFragment
}
val navController = navHostFragment.navController
navController.setGraph(graph, intent.extras)
Remove startDestination from nav_graph.xml
?xml version="1.0" encoding="utf-8"?>
<!-- app:startDestination="#id/oneFragment" -->
<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_main">
<fragment
android:id="#+id/DetailFragment"
android:name="DetailFragment"
android:label="fragment_detail"
tools:layout="#layout/fragment_detail"/>
<fragment
android:id="#+id/OtherDetailFragment"
android:name="OtherDetailFragment"
android:label="fragment_other_detail"
tools:layout="#layout/fragment_other_detail"/>
</navigation>
I found a solution for this, but it's ugly. I guess this it to be expected with an alpha library, but I hope Google looks into simplifying/fixing this as this is a pretty popular navigation pattern.
Alexey's solution did not work for me. My problem was that I have up arrows showing on my Actionbar by using:
NavigationUI.setupActionBarWithNavController(this, navController)
If I did as Alexey suggests above, my new start fragment still had a arrow pointing to my initial start fragment. If I pressed that up arrow my app would sort-of restart, transitioning to itself (the new start fragment)
Here is the code needed to get to what I wanted which was:
Fragment #1 is where my application initially starts
I can do an Auth check in Fragment #1 and then programmatically change the start to fragment #2.
Once in Fragment #2 there is no up arrow and pressing the back button does not take you to Fragment #1.
Here is the code that accomplishes this. In my Activity's onCreate:
// Setup the toolbar
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
// Configure the navigation
val navHost = nav_host_fragment as NavHostFragment
graph = navHost.navController
.navInflater.inflate(R.navigation.nav_graph)
graph.startDestination = R.id.welcomeFragment
// This seems to be a magical command. Not sure why it's needed :(
navHost.navController.graph = graph
NavigationUI.setupActionBarWithNavController(this, navHost.navController)
and also:
fun makeHomeStart(){
graph.startDestination = R.id.homeFragment
}
Then in Fragment #1's onActivityCreated, per Alexey's suggestion:
override fun onActivityCreated(savedInstanceState: Bundle?) {
...
// Check for user authentication
if(sharedViewModel.isUserAuthenticated()) {
(activity as MainActivity).makeHomeStart() //<---- THIS is the key
val navOptions = NavOptions.Builder()
.setPopUpTo(R.id.welcomeFragment, true)
.build()
navController.navigate(R.id.action_welcomeFragment_to_homeFragment,null,navOptions)
} else {
navController.navigate(R.id.action_welcomeFragment_to_loginFragment)
}
}
The key code is:
(activity as MainActivity).makeHomeStart() which just runs a method in the activity that changes the graphs startDestination. I could clean this up and turn it into an interface, but I'll wait for Google and hope they improve this whole process. The method 'setPopUpTo' seems poorly named to me and it's not intuitive that your naming the fragment that is getting cut out of the graph. It's also strange to me that they're making these changes in navOptions. I would think navOptions would only relate to the navigation action they're connected to.
And I don't even know what navHost.navController.graph = graph does, but without it the up arrows return. :(
I'm using Navigation 1.0.0-alpha06.
You can also try the followings.
val navController = findNavController(R.id.nav_host_fragment)
if (condition) {
navController.setGraph(R.navigation.nav_graph_first)
} else {
navController.setGraph(R.navigation.nav_graph_second)
}
Instead of trying to pop start destination or navigate manually to target destination, it would be better to have another navigation graph with different workflow.
This would be even better for the case when you want completely different navigation flow conditionally.
You don't really need to pop the Splash Fragment. It can remain there for the rest of your App life. What you should do is from the Splash Screen determine which next Screen to Show.
In the picture above you can ask in the Splash Screen State if there is a saved LoginToken. In case is empty then you navigate to the Login Screen.
Once the Login Screen is done, then you analyze the result save the Token and navigate to your Next Fragment Home Screen.
When the Back Button is Pressed in the Home Screen, you will send back a Result message to the Splash Screen that indicates it to finish the App.
Bellow code may help:
val nextDestination = if (loginSuccess) {
R.id.action_Dashboard
} else {
R.id.action_NotAuthorized
}
val options = NavOptions.Builder()
.setPopUpTo(R.id.loginParentFragment, true)
.build()
findNavController().navigate(nextDestination, null, options)
For those who have a navigation xml file with similar content to this:
<?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_home">
<fragment
android:id="#+id/nav_home"
android:name="HomeFragment"
android:label="#string/menu_home"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/nav_users"
android:name="UsersFragment"
android:label="#string/users"
tools:layout="#layout/fragment_users" />
<fragment
android:id="#+id/nav_settings"
android:name="SettingsFragment"
android:label="#string/settings"
tools:layout="#layout/fragment_settings" />
</navigation>
suppose current fragment opened is the home fragment and you want to navigate to users fragment, for that just call in the setOnClickListener of the element that you want to navigate to the navigate method from the nav controller similar to this code:
yourElement.setOnClickListener {
view.findNavController().navigate(R.id.nav_users)
}
that will make the app navigate to that other fragment and will also handle the title in the toolbar.
Okay, after messing with this for a bit I found a solution that worked for me that didn't require a ton of work.
It appears two things MUST be in place for it function as if your secondFragment is your start destination.
use the ALTERNATIVE option in the accepted post
<fragment
android:id="#+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment"
app:popUpTo="#+id/firstFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="#+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
The above will remove firstFragment from the stack and inflate secondFragment when moving. The app cannot step back to firstFragment anymore BUT your left with secondFragment showing a back arrow as #szaske stated.
This is what made the difference. I previously defined my AppBarConfig using the NavigationController.graph like so
// Old code
val controller by lazy { findNavController(R.id.nav_host_fragment) }
val appBarConfig by lazy { AppBarConfiguration(controller.graph) }
Updating it to define a set of top-level destinations rectified the issue of showing the back arrow on secondFragment instead of a hamburger menu icon.
// secondFragment will now show hamburger menu instead of back arrow.
val appBarConfig by lazy { AppBarConfiguration(setOf(R.id.firstFragment, R.id.secondFragment)) }
Setting the start destination may or may not have negative implications in your project so do it as needed however in this example we do not need to do so. If it makes you warm and fuzzy to ensure that your graph has the correct start fragment defined, you can do it like so.
controller.graph.startDestination = R.id.secondFragment
Note: Setting this does not prevent the back arrow from occurring in secondFragment and from what I have found seems to have no effect on navigation.
I tried to modify code in startDestination.
It works well, but It does not keep the activity, the Navigation component does not restore fragment stack.
I resolved this problem with a dummy startDestination
startDestination is EmptyFragment(just a dummy)
EmptyFragment to FirstFragment action require popUpTo=EmptyFragment and popUpToInclusive=true
NavGraph image
In Activity.onCreate()
if (savedInstanceState == null) {
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)!!
val navController = navHost.findNavController()
if (loginComplete) {
navController.navigate(
R.id.action_emptyFragment_to_FirstFragment
)
} else {
navController.navigate(
R.id.action_emptyFragment_to_WelcomeFragment
)
}
}
when Activity is recreated, savedInstanceState is not null and fragment is restored automatically.

Categories

Resources