Navigation Component .popBackStack() with arguments - android

I have Two fragment. SecondFragment and ThirdFragment. Actually I use the Navigation Component for passing value between fragments. Like this:
SecondFragment:
val action = SecondFragmentDirections.action_secondFragment_to_thirdFragment().setValue(1)
Navigation.findNavController(it).navigate(action)
Here is how I read the value from the ThirdFragment:
arguments?.let {
val args = ThirdFragmentArgs.fromBundle(it)
thirdTextView.text = args.value.toString()
}
It's work fine. Now my stack is look like this:
ThirdFragment
SecondFragment
There is any option for pass value from the opened ThirdFragment to the previous SecondFragment with the new Navigation Component? (When ThirdFragment is finishing)
I know about onActivityResult, but If Nav.Component serve better solution than I want use that.
Thank you!

It's a bit late for this answer but someone may find it useful. In the updated versions of the navigation component library it is now possible to pass data while navigating back.
Suppose the stack is like this
FragmentA --> FragmentB.
We are currently now in FragmentB and we want to pass data when we go back to FragmentA.
Inside FragmentAwe can create an observer with a key:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val navController = findNavController()
// Instead of String any types of data can be used
navController.currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")
?.observe(viewLifecycleOwner) {
}
}
Then inside FragmentB if we change its value by accessing previous back stack entry it will be propagated to FragmentA and observer will be notified.
val navController = findNavController()
navController.previousBackStackEntry?.savedStateHandle?.set("key", "value that needs to be passed")
navController.popBackStack()

Just came across setFragmentResult(), pretty easy to use. The docs on this are here.
If you are navigating: Fragment A -> Fragment B -> Fragment A
Add this to fragment A:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setFragmentResultListener("requestKey") { requestKey, bundle ->
shouldUpdate = bundle.getBoolean("bundleKey")
}
}
Then in fragment B add this line of code:
setFragmentResult("requestKey", bundleOf("bundleKey" to "value to pass back"))
// navigate back toFragment A
When you navigate back to fragment A the listener will trigger and you'll be able to get the data in the bundle out.

What you are asking for is an anti-pattern. You should either
navigate to the second fragment again with the new values you would like to set
use the third fragment ins a separate activity and start it with startActivityForResult()
use a ViewModel or some kind of singleton pattern to hold on to your data (make sure you clear the data after you no longer need it)
these are some of the patterns that came to my mind. Hope it helps.

As described here:
When navigating using an action, you can optionally pop additional destinations off of the back stack. For example, if your app has an initial login flow, once a user has logged in, you should pop all of the login-related destinations off of the back stack so that the Back button doesn't take users back into the login flow.
To pop destinations when navigating from one destination to another, add an app:popUpTo attribute to the associated element. app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate(). The attribute value is the ID of the most recent destination that should remain on the stack.
<fragment
android:id="#+id/c"
android:name="com.example.myapplication.C"
android:label="fragment_c"
tools:layout="#layout/fragment_c">
<action
android:id="#+id/action_c_to_a"
app:destination="#id/a"
app:popUpTo="#+id/a"
app:popUpToInclusive="true"/>
</fragment>

Related

Android onBackPressed adds Fragment instead of replacing

In my app, I have a TopActionBar fragment that is loaded on the MainActivity that loads a MaterialToolbar, along with my navigation drawer. I have a FrameLayout in this fragment that I replace with fragments to navigate between pages. When I replace a fragment (using a function I have defined in a utils.kt file), I am tracking the fragments that are loaded for the first time and adding them to the BackStack so that I can pop them and prevent duplicates of that fragment from being added to the BackStack. Here is the relevant logic for how that is being managed in my Utils.kt file:
fun replaceFragment(destinationFragment : Fragment,
currentFragment: String,
title : String,
initialLaunch: Boolean = false
) {
val destinationFragmentName = destinationFragment.javaClass.simpleName
val fragmentTag : Fragment? = fragmentManager.findFragmentByTag(destinationFragmentName)
if(destinationFragmentName !== currentFragment || initialLaunch) {
val fragmentTransaction = fragmentManager.beginTransaction()
// some logic to determine animations depending on the fragment being replaced
if (fragmentTag == null) {
fragmentTransaction.replace(R.id.frame_layout, destinationFragment, destinationFragmentName)
fragmentTransaction.addToBackStack(destinationFragmentName)
} else { // re-use the old fragment
fragmentTransaction.replace(R.id.frame_layout, destinationFragment, destinationFragmentName)
}
fragmentTransaction.commit()
}
}
And then this is how I have overwritten the onBackPressed function in my MainActivity:
override fun onBackPressed() {
if (fragmentManager.backStackEntryCount > 0) {
fragmentManager.popBackStackImmediate()
} else {
super.onBackPressed()
}
}
A couple of things aren't working properly. Take this example flow of fragments below:
A -> B -> C -> B -> C
When I press back I get this flow:
BC -> AC -> App Close
Here multiple Fragments are being displayed at the same time.
What I expect to happen is:
C -> B -> A -> App Close
Can someone maybe offer some insights into why this is occurring and what I can do to fix this? If I don't conditionally addToBackStack, and just addToBackStack for every single Fragment I replace, it works fine, but I don't want the multiple copies in the BackStack. I need to keep the most recent instance of each Fragment in the BackStack. So in my example:
A -> B -> C -> B -> C
The BackStack would no longer have the first C, just the most recent one.
As per the FragmentManager guide:
When you call addToBackStack() on a transaction, note that the transaction can include any number of operations, such as adding multiple fragments, replacing fragments in multiple containers, and so on. When the back stack is popped, all of these operations are reversed as a single atomic action. If you've committed additional transactions prior to the popBackStack() call, and if you did not use addToBackStack() for the transaction, these operations are not reversed. Therefore, within a single FragmentManager, avoid interleaving transactions that affect the back stack with those that do not.
So what you are experiencing is the operation you did with addToBackStack being reversed (causing your original copy of B to reappear) while not touching the new C you did not use addToBackStack.
The FragmentManager's back stack is just that: a stack. That means you can't remove B from the stack unless it is at the top of the back stack. That means there's no way to remove B from the middle of the stack without using something like the support for multiple back stacks to completely swap between independent back stacks.
If you just want to make sure there is only one copy of B on the top of the stack, you'll want to popBackStack() to remove the topmost if the names are the same before unconditionally using addToBackStack() on your new instance.

Get parent fragment from child when using Navigation Component

I need to transfer data from one fragment to another. Now the recommended way to do this is to use a shared ViewModel. To get the same instance available in both fragments, common owner is needed. As it can be their common Activity. But with this approach (In the case of Single Activity), the ViewModel instance will live throughout the entire application. In the classic use of fragments, you can specify ViewModelProvider (this) in the parent fragment, and ViewModelProvider (getParentFramgent ()) in the child. Thus, the scope of ViewModel is limited to the life of the parent fragment. The problem is that when using Navigation Component, getParentFramgent () will return NavHostFragment, not the parent fragment. What do I need to do?
Code samples:
Somewhere in navigation_graph.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/nav"
app:startDestination="#id/mainMenuFragment">
<fragment
android:id="#+id/mainMenuFragment"
android:name="com.mypackage.mainmenu.MainMenuFragment"
android:label="MainMenu"
tools:layout="#layout/fragment_main_menu">
<action
android:id="#+id/start_game_fragment"
app:destination="#id/gameNav" />
</fragment>
<navigation
android:id="#+id/gameNav"
app:startDestination="#id/gameFragment">
<fragment
android:id="#+id/gameFragment"
android:name="com.mypackage.game.GameFragment"
android:label="#string/app_name"
tools:layout="#layout/fragment_game"/>
</navigation>
</navigation>
Somewhere in MainMenuFragment:
override fun startGame(gameSession: GameSession) {
//This approach doesn't work
ViewModelProvider(this)[GameSessionViewModel::class.java].setGameSession(
gameSession
)
findNavController().navigate(R.id.start_game_fragment)
}
GameFragment:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
gameSessionViewModel =
ViewModelProvider(requireParentFragment())[GameSessionViewModel::class.java].apply {
val session = gameSession.value
)
}
}
EDIT:
I can use NavHostFragment(returned from getParentFragment()) as a common for all fragments, but then, as in the case of Activity, ViewModel.onCleared() will not be called when the real parent fragment finishes.
There's really no way to do this.
Here is a code snippet from androidx.navigation.fragment.FragmentNavigator:
public NavDestination navigate(#NonNull Destination destination, #Nullable Bundle args,
#Nullable NavOptions navOptions, #Nullable Navigator.Extras navigatorExtras) {
// ...
final FragmentTransaction ft = mFragmentManager.beginTransaction();
// ...
ft.replace(mContainerId, frag);
ft.setPrimaryNavigationFragment(frag);
// ...
}
Under the hood, the FragmentManager is used, which calls replace(). Therefore, the child fragment is not added, but is replaced with a new one, so it will not be in getParentFramgent().
I faced the same problem and after researching and experimenting, I found the solution.
You simply have to call this while scoping your ViewModel which will resolve to your fragment where you have created the navigation host fragment.
ViewModelProvider(getParentFragment().getParentFragment())
or more appropriately
ViewModelProvider(requireParentFragment().requireParentFragment())
(to avoid NPE)
This is because child fragment's parent is NavHostFragment and NavHostFragment's parent is ParentFragment.
I tested this and it's working fine for me
for those of you who are bothered with this problem, here is the answer that worked for me:
suppose that you go from fragment A to fragment B, and you want to use a shared ViewModel for fragment A and B, and in this case, A is a fragment and B is a dialogFragment.
you can initialize ViewModel in fragment A:
ViewModelProvider(this).get(AviewModel::class.java)
and in order to use it on fragment B, initialize the ViewModel in fragment B like this:
ViewModelProvider(requireParentFragment().childFragmentManager.fragments[0]).get(AviewModel::class.java)
TL;DR:
requireParentFragment() returns NavHostFragment which hosts all the navigation of the current navigation.
requireParentFragment().childFragmentManager returns FragmentManagerImpl which seems to be the container for all fragments.
requireParentFragment().childFragmentManager.fragments returns a mutable list of fragments that are in the stack, so you can iterate through the list to see the fragments that are living in stack.

Why Android Navigation Component screen not go back to previous Fragment,but a method in onViewCreated of previos Fragment being called?

I have 2 fragment call CreateRoomFragment and DisplayPhotoFragment,the navigation graph is look like this:
<navigation>
<fragment
android:id="#+id/createRoomFragment"
android:name="package.room.CreateRoomFragment"
android:label="Create a room"
tools:layout="#layout/fragment_create_room">
<action
android:id="#+id/action_createRoomFragment_to_roomFragment"
app:destination="#id/roomFragment" />
<action
android:id="#+id/action_createRoomFragment_to_displayPhotoFragment"
app:destination="#id/displayPhotoFragment" />
</fragment>
<fragment
android:id="#+id/displayPhotoFragment"
android:name="package.fragment.DisplayPhotoFragment"
android:label="fragment_display_photo"
tools:layout="#layout/fragment_display_photo" >
<argument android:name="bitmap"
app:argType="android.graphics.Bitmap"/>
</fragment>
So when I wanna to move from CreateRoomFragment to DisplayPhotoFragment,I use the do as below:
NavDirections action = CreateRoomFragmentDirections.actionCreateRoomFragmentToDisplayPhotoFragment(selectedPhoto);
Navigation.findNavController(view).navigate(action);
Doing this,I can navigate to DisplayPhotoFragment.
But when I press back button of the device and also the Back arrow from the toolbar,it cant go back to CreateRoomFragment.
I tried this,but still unable to back to previous fragment:
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
new OnBackPressedCallback(true) {
#Override
public void handleOnBackPressed() {
navController.navigateUp(); //I tried this
navController.popBackStack(R.id.createRoomFragment,false); //and also this
}
});
Main Problem now:
By using the code above,the screen didnt go back to previous Fragment(CreateRoomFragment).It still stuck in DisplayPhotoFragment,but at the same time,an API method in CreateRoomFragment onViewCreated section is being called.
What causing this? and how can I solve this problem?
I had the same problem. For me the issue was that I was using a LiveData boolean to decide when to go to the next fragment. When I then navigated back/up the boolean was still true so it would automatically navigate forward again.
Android maintains a back stack that contains the destinations you've visited. The first destination of your app is placed on the stack when the user opens the app. Each call to the navigate() method puts another destination on top of the stack. Tapping Up or Back calls the NavController.navigateUp() and NavController.popBackStack() methods, respectively, to remove (or pop) the top destination off of the stack.
NavController.popBackStack() returns a boolean indicating whether it successfully popped back to another destination. The most common case when this returns false is when you manually pop the start destination of your graph.
When the method returns false, NavController.getCurrentDestination() returns null. You are responsible for either navigating to a new destination or handling the pop by calling finish() on your Activity.
When navigating using an action, you can optionally pop additional destinations off of the back stack by using popUpTo and popUpToInclusive parameter of the action.
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (true == conditionForCustomAction) {
CustomActionHere()
} else NavHostFragment.findNavController(this#MyFragment).navigateUp();
}
}
requireActivity().onBackPressedDispatcher.addCallback(
this, onBackPressedCallback
)
...
}
The best solution for handling navigation using live data is to use the SingleLiveEvent.
You can always use this class which is an extension of MutableLiveData.
https://gist.githubusercontent.com/cdmunoz/ebe5c4104dadc2a461f512ea1ca71495/raw/a17f76754f86a4c0b1a6b43f5c6e6d179535e627/SingleLiveEvent.kt
For a detail run down of this check:
https://proandroiddev.com/singleliveevent-to-help-you-work-with-livedata-and-events-5ac519989c70
Had a similar issue. We still have multiple activities with nav component.
So imagine activity A -> activity B, activity B has its own nav and fragments. When the initial fragment tries to pop the back stack there is nowhere to pop back to and the nav controller does not know to finish the activity. So one solution I found was to do
if (!findNavController().popBackStack()) activity?.finish()
If nav controller can not pop back it will finish activity.
You can use MutableSharedFlow instead on MutableLiveData if you want to observe the Event only once.
in your viewModel:
private val _events = MutableSharedFlow<Event>()
val events = _events.asSharedFlow() // read-only public view
suspend fun postEvent() {
_events.emit(event) // suspends until subscribers receive it
}
In your Activity/Fragment class:
lifecycleScope.launchWhenStarted {
viewModel.events.collect {
}
}
viewModel.postEvent()
This will prevent observing data continuously when going back to fragment.

how to pass a value back to previous fragment destination using Android navigation component?

let sat I have some destinations like this
from fragment A --> to fragment B --> to fragment C
I can use Safe Args to pass data from fragment A to fragment B. and also using safe args from fragment B to fragment C.
what if I want to bring a string that generated in fragment C back to fragment B or to fragment A ?
to navigate from fragment C to fragment B, I use code:
Navigation.findNavController(fragmentView).navigateUp()
and to navigate from fragment C to fragment A, I use code:
Navigation.findNavController(view).popBackStack(R.id.fragmentA, false)
so how to pass a value back to previous fragment destination ? do I have to make an action back from fragment C to fragment B and pass the value through safe args ?
really need your help. Thank you very much :)
You can use the below snippet for sending data to previous fragment.
Fragment A observing the data:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe(viewLifecycleOwner) { data ->
// Do something with the data.
}
}
Fragment B sending the data:
findNavController().previousBackStackEntry?.savedStateHandle?.set("key", data)
findNavController().popBackStack()
I also wrote extensions for this.
fun <T : Any> Fragment.setBackStackData(key: String,data : T, doBack : Boolean = true) {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, data)
if(doBack)
findNavController().popBackStack()
}
fun <T : Any> Fragment.getBackStackData(key: String, result: (T) -> (Unit)) {
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)?.observe(viewLifecycleOwner) {
result(it)
}
}
Usage:
Fragment A:
getBackStackData<String>("key") { data ->
// Do something with the data.
}
Fragment B:
setBackStackData("key",data)
Note: I am using String as data. You may use any other type of variable.
Note: If you are going to use a Class as data, don't forget to add #Parcelize annotation and extend Parcelable.
i have just came across the same problem and have several options i can propose (currently considering myself which ones is best for my use case).
create a navigation action from fragment C back to fragment A. note that if that's all you do, your stack will now be: A-B-C-A. to avoid this, you can use popUpTo and PopUpToInclusive. see the documentation.
the disadvantage of this method is that fragment A will be cleared no matter what, and would have to re-load (and fetch all its' data again).
use a shared ViewModel between for your fragments, and observe the required value with LiveData. in this scenario, fragment C will update a LiveData value in the shared ViewModel, which fragment A observes. now when you go back to fragment A, your observer will be triggered with the value set by fragment C.
similar to option 2, if you are using an external data source (like a Room database) you can observe changes using LiveData in fragment A. all fragment C has to do in this case is update the data source, and fragment A will automatically be updated through the LiveData

Navigation popUpTo and PopUpToInclusive aren't clearing the backstack

I'm new to the Android Jetpack Navigation architecture. I'm trying it out on a new app. There's one activity and a few fragments, two of them are login screen and email login screen. I defined those fragments in my navigations XML. The flow of the app is as follows:
Login screen → Email Login screen
What I want is, after navigating to the email login screen, when I press back, the app exits. Meaning the back-stack for login screen is removed. I know login screens aren't supposed to work that way, but I'm still just figuring things out.
I followed the documentation from Google's Get started with the Navigation component. It said, using app:popUpTo and app:popUpToInclusive="true" is supposed to clear the backstack, yet when I press back on email login screen, it still goes back to login instead of exiting.
So, here's what I've tried.
nav_main.xml
<fragment android:id="#+id/loginFragment"
android:name="com.example.myapp.ui.main.LoginFragment"
android:label="#string/login"
tools:layout="#layout/fragment_login" >
<action
android:id="#+id/action_login_to_emailLoginFragment"
app:destination="#id/emailLoginFragment"
app:popEnterAnim="#anim/slide_in_right"
app:popExitAnim="#anim/slide_out_right"
app:popUpTo="#+id/emailLoginFragment"
app:popUpToInclusive="true"/>
</fragment>
<fragment android:id="#+id/emailLoginFragment"
android:name="com.example.myapp.ui.main.EmailLoginFragment"
android:label="EmailLoginFragment"
tools:layout="#layout/fragment_login_email" />
LoginFragment.kt
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding.emailLoginButton.setOnClickListener {
findNavController().navigate(R.id.action_login_to_emailLoginFragment)
}
return binding.root
}
I gave a click event to a button. In it, I used the Navigation Controller to navigate to the email login screen by giving it the action's ID. In the <action>, there are app:popUpTo and app:popUpToInclusive="true".
After reading the documentation over and over, as well as reading plenty of StackOverflow questions, I found those properties are supposed to remove my login screen off the back-stack. But they don't. The button does navigate to the email login screen, but when I press back, it still goes back to login screen instead of exiting the app. What am I missing?
<action
android:id="#+id/action_login_to_emailLoginFragment"
app:destination="#id/emailLoginFragment"
app:popEnterAnim="#anim/slide_in_right"
app:popExitAnim="#anim/slide_out_right"
app:popUpTo="#+id/loginFragment"
app:popUpToInclusive="true"/>
Your popUpTo is going back to the email login, and then popping it because of the inclusive.
If you will change the popUpTo to your login fragment, it will be navigated back to, and popped as well because of the inclusive flag, which will result in your desired behaviour.
I write this answer for people who have not completely understood the
way popUpTo works and I hope its example helps someone because most
examples for navigation are repetitive in most sites and do not show
the whole picture.
In any <action> if we write a value for app:popUpTo, it means we want to delete some of the fragments from the back stack just after completing the action, but which fragments are going to be removed from the back stack when action is completed?
Its order is Last In First Out so:
All fragments between the last fragment and the fragment defined in popUpTo will be removed.
And if we add app:popUpToInclusive="true", then the fragment defined
in popUpTo will also be removed.
Example:
Consider fragments from A to G in a navigation graph like this:
A->B->C->D->E->F->G
We can go from A to B and then from B to C and so on. Consider the following two actions:
An action E->F we write:
<action
...
app:destination="#+id/F"
app:popUpTo="#+id/C"
app:popUpToInclusive="false"/>
And for F->G we write:
<action
...
app:destination="#+id/G"
app:popUpTo="#+id/B"
app:popUpToInclusive="true"/>
Then after going from E to F using the action E->F, the fragments between the last fragment (F) and C (which is defined in popUpTo of E->F) will be removed. The fragment C will not be removed this time because of app:popUpToInclusive="false" so our back stack becomes:
A->B->C->F (F is currently on Top)
Now if we go to fragment G using action F->G :
all fragments between the last fragment(G) and B (which is defined in popUpTo of F->G ) will be removed but this time the fragment B will also be removed because in F->G action we wrote app:popUpToInclusive="true" . so back stack becomes:
A->G (G is on top now)
These 2 lines make the trick works:
If you want to go from A to B and expect to finish A:
You need to call B with this action:
<fragment
android:id="#+id/fragmentA"
tools:layout="#layout/fragment_a">
<action
android:id="#+id/action_call_B"
app:destination="#+id/fragmentB"
app:popUpTo="#id/fragmentA"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="#+id/fragmentB"
tools:layout="#layout/fragment_b">
</fragment>
If you put log to your fragments you can see that fragmentA is destroyed after calling fragmentB with this action.
You can do it in XML just like this answer does, or you can also do it programmatically:
NavOptions navOptions = new NavOptions.Builder().setPopUpTo(R.id.loginRegister, true).build();
Navigation.findNavController(mBinding.titleLogin).navigate(R.id.login_to_main, null, navOptions);
Let's say that your app has three destinations—A, B, and C—along with actions that lead from A to B, B to C, and C back to A. The corresponding navigation graph is shown in figure
With each navigation action, a destination is added to the back stack. If you were to navigate repeatedly through this flow, your back stack would then contain multiple sets of each destination (A, B, C, A, B, C, A, and so on). To avoid this repetition, you can specify app:popUpTo and app:popUpToInclusive in the action that takes you from destination C to destination A, as shown in the following example:
<fragment
android:id="#+id/c"
android:name="com.example.myapplication.C"
android:label="fragment_c"
tools:layout="#layout/fragment_c">
<action
android:id="#+id/action_c_to_a"
app:destination="#id/a"
app:popUpTo="#+id/a"
app:popUpToInclusive="true"/>
After reaching destination C, the back stack contains one instance of each destination (A, B, C). When navigating back to destination A, we also popUpTo A, which means that we remove B and C from the stack while navigating. With app:popUpToInclusive="true", we also pop that first A off of the stack, effectively clearing it. Notice here that if you don't use app:popUpToInclusive, your back stack would contain two instances of destination A
popUpTo its to define the place that you want to go when you press back. If you set popUpInclusive = true, the navigation skipe that place too ( in popUpTo ).
Sample: A -> B -> A
FragmentB.kt
Attempts to pop the controller's back stack
private fun popBackStackToA() {
if (!findNavController().popBackStack()) {
// Call finish on your Activity
requireActivity().finish()
}
}
Back Stack
I faced a similar problem and my approach was simple. In the navigation graph, you have to designate the starting screen. Mine was:
app:startDestination="#id/webview"
It's called the start destination, it is the first screen users see when opening your app, and it's the last screen users see when exiting your app.
If you do not wish your login activity to be shown as you exit the app, just remove it as the start destination and use the fragment that you wish to show last in your case, It's the Email Login screen.
<?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"
app:startDestination="#id/Email Login screen">
Also, make sure you override the onBackPressed() method from the host activity code as:
override fun onBackPressed() {
finish()
super.onBackPressed()
}
Now that you have removed the login fragment as the start destination, it's now not obvious what fragment will be shown first when the app opens.
Add a method to implement that in the host activity and call it from the oncreate(). In my case,i created initContent() to handle that logic. This was the code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
if (savedInstanceState == null) {
initContent()
}
}
private fun initContent() {
if (isNetworkConnected()) {
navController.navigate(R.id.webView)
} else {
navController.navigate(R.id.noInternetFragment)
}
}
Hope this helps someone.

Categories

Resources