I have an activity that is using the navigation component to flow through my fragments to get info from the user in a wizard style. I have a dead end fragment in my flow where I tell the user why they can't continue and I want to provide a done/cancel button that finishes the activity that the nav controller is in and leaves the user at the screen they left off on.
I tried adding the activity they launch the flow from as an action destination but that launches the activity as a new activity and isn't where the user left from.
I can grab the activity from the fragment and call finish() on that activity from the button click but that didn't seem like the way one is supposed to use the nav graph. Am I wrong? Is there a way to say in a nav graph direction to just exit the everything?
There's no navigate() operation that will pop activities off the stack - the only back stack that the NavController is aware of is the internal back stack it manages.
If you want to finish an activity, call finish() on your activity.
Related
I have been using android navigation component for the first time and I am new to the Android architecture component as well. As far as I have seen, the navigation component in android architecture uses fragment predominantly for navigation within the same activity. I was trying to navigate from one activity to another using the navigation component:
activity.finish()
Navigation.findNavController(btnView).navigate(R.id.activity)
Here R.id.activity is the id of the activity defined in the navigation graph XML file.
When I press the back button, I was still able to see the previous screen. My question is how the back stack works in the navigation component and why my first activity appears even though the destroy method of the activity is called (due to activity.finish()) ?
I can answer your second part for the first part someone will better understanding will explain you.
Your activity is not finished by executing this below method because if it was finished then you don't see it on back stack.
activity.finish()
finish current activity after navigate method. Below will be the correct way finishing current activity.
btn.setOnClickListener{
Navigation.findNavController(btnView).navigate(R.id.secondActivity)
(activity as currentActivity).finish()
}
When I open the app from a deeplink (user clicks on URL) and press back button I expect user to navigate to a previous fragment in my navigation graph but it just exits the app.
The documentation says that back navigation should work the same way as if it the user got to that screen naturally.
Can I somehow specify the desired backstack in my navigation graph? Or can be backstack formed automatically after a deeplink? For older version of the library I found out that after back press it should navigate to the root of my navigation graph but that does not happen.
I’m using the navigation library from Android architecture components (version 1.0.0-beta01).
I found out what's going on here, for explicit deep links its supposed to go to a new back stack which is what you app would have if a user had naturally navigated to the view not the existing back stack (existing stack is cleared.
When a user opens your app via an explicit deep link, the task back stack is cleared and replaced with the deep link destination. When nesting graphs, the start destination from each level of nesting—that is, the start destination from each element in the hierarchy—is also added to the stack. This means that when a user presses the Back button from a deep link destination, they navigate back up the navigation stack just as though they entered your app from its entry point.
For implicit its a bit strange. You can make it do what explicit does but setting Intent.FLAG_ACTIVITY_NEW_TASK otherwise the back button and the navigation up button do two separate things:
The back button will do as you might expect, it will go back in your apps existing back stack and load that fragment.
The up button however will clear the a back stack and make a new one as if it was an explicit link.
If the flag is not set, you remain on the task stack of the previous app where the implicit deep link was triggered. In this case, the Back button takes you back to the previous app, while the Up button starts your app's task on the hierarchical parent destination within your navigation graph.kquote
Source: Android Documentation
As describe here back button should return to the previous fragment, you can set it manually in Java like this: button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));
In Kotlin like that: button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null))
The Android system maintains a back stack containing the last visited destination. 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 the top of the stack. Conversely, pressing the Up or Back button calls the NavController.navigateUp() and NavController.popBackStack() methods, respectively, to pop the top destination off of the stack.
Make sure that you are using NavHostFragment and not <fragment> in your hosting fragment activity.
I'm currently learning the Activity Lifecyle. I noticed the following:
I have two Activitys, A and B.
When I open Activity B from Activity A, A gets stopped and B gets created and started.
When I press the Back Button on my device, B gets destroyed and A get restarted.
But when I use the Back / Up Botton of the Actionbar instead, B gets destroyed, A gets destroyed and then onCreate() is called.
Why gets A destroyed instead of restarted, when using the Up Botton in the ActionBar?
I hope my question is clear, if not please comment.
When you press the BACK button, this calls onBackPressed() in the current Activity. The default behaviour of that method (if not overridden in the Activity) is to call finish() on the Activity. This finishes the Activity and resumes the Activity which is underneath it.
The UP button is calling startActivity() with an Intent that is built like this:
Intent intent = new Intent(this, TargetActivityForUpButton.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
This code will remove all activities in the stack back to, and including, TargetActivityForUpButton. It then creates a new instance of TargetActivityForUpButton and launches that Actvity (you will see onCreate(), onStart(), onResume() called on the Activity.
See also the section "Navigate up to parent activity" in https://developer.android.com/training/implementing-navigation/ancestral
The device's back button is actually taking you back (to the previous activity). The action bar back button works similarly to an "Up" button (within the hierarchy of your app). This is why the action bar's back button won't take you outside of the app, whereas the device's back button will carry on taking you back, even outside of the app. The action bar exists within your app so it follows the activity's lifecycle methods and starts from scratch each time you go back, whereas the device is restarting from where it stopped.
EDIT:
The Back button appears in the system navigation bar and is used to navigate, in reverse chronological order, through the history of screens the user has recently worked with. It is generally based on the temporal relationships between screens, rather than the app's hierarchy.
(Read more here)
I have an app with a main menu at bottom; I can't figure out how should I manage the activity stack, because every button opens an activity, and each activity can start more activities, and i was looking for a management in the style of the current Instagram's app. It looks like (in the Instagram app) that every activity started by each button in the bottom menu opens a new activity stack, but when you press back button, it navigates in the reverse order you called every activity.
Sorry for my bad explanation, i hope that you can understand my aim.
You could check out Instagram Android app to figure out what is my goal.
My current implementation uses a MainActivity with a Fragment for the first menu button (Qui in giro->"Nearby"), but i probably should change this approach.
Thanks.
1) Firstly you will have to decide what will be your main activity.
2) Now use this main activity like as star topology. Means this main activity will be center activity.
3) Use to finish() method for finish back stack before receiving at this center activity.
4) After it if you open another side of your main activity than you will see only new back stack will be displayed after pressing back button for receiving at main activity again.
The android docs said that I can use the class TaskStackBuilder to recreate a back navigation behavior when an inner activity is launched from another way that the normal flow (from the main home activity), for example when the user click a notification bar:
"Ordinarily, the system incrementally builds the back stack as the user navigates from one activity to the next. However, when the user enters your app with a deep link that starts the activity in its own task, it's necessary for you to synthesize a new back stack because the activity is running in a new task without any back stack at all." - developers.android.com
That is ok, but I have an application most compose of fragments and few activities. I wanted to launch a inner fragment from a notification (call it FragmentC), so when the user click the notification in the notification bar my application open the baseActivity, and this activity should recreate the FragmentC as the first showing (I think to do this by passing a some args from the notification Intent and ask it in the baseActivity to replace the fragment showing), but in this scenary, when the user navigate to backward the application finish because there is only one activity alive and then the home screen is show to the user, that is wrong, I wanted to recreate a flow of fragments in this manner:
Notification clicked by the user ::
BaseActivity -> FragmentA -> FragmentB -> FragmentC (Visible)
Then the user navigate back ::
BaseActivity -> FragmentA -> FragmentB (Visible)
User navigate back ::
BaseActivity -> FragmentA (Visible)
User navigate back ::
(Application Finish, showing home screen)
Is there a way to launch a inner fragment from a notification (in the notification bar), and recreate a "normal" back navigation flow for fragments like using the TaskStackBuilder class? or How would you do it in a clean way?
I suppose that I can do this manually in the baseActivity when I detect that the fragment is launched from a notification, but this is dirty code for me, and I know that there is a TaskStackBuilder class for do this in a more clean way, but I can't found nothing about how using it with fragments transactions. :S
Sources:
https://developer.android.com/training/implementing-navigation/temporal.html#SynthesizeBackStack
https://developer.android.com/training/implementing-navigation/temporal.html#back-fragments
I've created a simple class that handles the navigation, but essentially, everything what you need it's create a transaction from the FragmentManager adding what normally you need, and then, use the addToBackStack to guarante that your fragment remains in the stack
FragmentTransaction ft = FragmentManager.beginTransaction();
ft.addToBackStack(""); //An optional name for this back stack state, or null.
ft.commit();
Now when you press the back button, automatically the previous fragment comes to foreground
You can clean your stack if you want using.
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
I think that this is the easiest way, hope that somebody else can complement or suggest something better.