This snippet of code:
#Override
public void onBackPressed() {
if( !getFragmentManager().popBackStackImmediate() ) super.onBackPressed();
}
What does this mean exactly? I looked in the docs and it says
"Like popBackStack(int, int), but performs the operation immediately
inside of the call. This is like calling executePendingTransactions()
afterwards."
But I don't know what this means, or what it means to have the negation in front of it, or what super.onBackPressed() is doing.
Returns true if there was something popped, else false.
Basically you are popping your backstack (cleaning the fragments on the history, so when you go back you will not go to the last fragment) and if theres no fragment on the backstack (no fragment on the history) you will do your super.backPressed.
The super.onBackpressed() will execute your activity onBackPressed (even if this code is called from a fragment, as there is no default code to do on your fragment onBackPressed().
If your activity extends a default Android activity it will go back to the last activity, if theres one, os get out of the app, if theres none.
pseudocode:
popBackStack() // clear the fragment history
if (somethingWasPopped) {
super.backPressed() // this will do what i said above
}
Probably the developer who done this was trying to make the user unable to get back to the last fragment when he press back. Like Activity1 -> Activity 2 (frag A -> frag B -> frag C). Now, user is on frag C, he will get back to Activity 1 (when he press back or click on back icon), instead of frag B.
Related
I've been struggling with a particular challenge which is as follows:
My app has an activity "A" which is considered the app's "main" activity. At a certain point, it launches an activity "B" which has an action available that should launch a fragment inside activity "A" (this won't always be the same fragment, it will depend on some data coming from our backend).
I can do this just fine by simply calling startActivity with the correct Intent, however, on pressing the back button, it goes back to A's "main fragment" (this is logic implemented inside of A's onBackButtonPressed()). Essentially, what should happen is as follows:
Activity A -> Activity B -> Activity A showing Fragment X -> press back -> Activity B
What happens when using startActivity to launch Activity A:
Activity A -> Activity B -> Activity A showing Fragment X -> press back -> Activity A showing the "main fragment". From here, if I press back again the app exits, which again is part of the implementation of A's onBackButtonPressed, however I've tried retrieving an extra from the intent which invoked A in order to conditionally bring back activity B but the Intent seemed to be empty of extras for reasons I can't figure out. I am sure I am correctly putting the extras in the Intent since activity A launches the correct fragment when invoked from B based on what I put there.
More things I've tried:
Launching the desired fragment directly from within B, however this way the fragment is not shown with the navigation bar that exists in A and seems to show the main contents of activity B behind the fragment's elements, which in user experience terms is undesirable.
Using the Intent.FLAG_ACTIVITY_REORDER_TO_FRONT flag, which seemed to make no difference whatsoever.
As this is part of my company's app which already has a decent degree of complexity, I'm not at liberty to provide you with useful code samples, and hopefully my description is sufficient for someone to aid me.
Additional information
targetApi="n"
Testing on Android 11
Activity A has launchMode "singleTask"
Activity B has launchMode "singleTop"
For the intended behavior:
Avoid using any launchMode, taskAffinity or activity flags, the default behavior is absolutely good for your requirements ("standard" is the default launch mode). So when you do the action in Activity B, a new instance of Activity A will be launched after putting B in backstack, which is the default behavior.
You should have a logic in Activity A's onBackPressed() such that: if the fragment X is visible, then it will exit the whole activity, otherwise it passes by calling super(). Something like the following:
In Activity A
#Override
public void onBackPressed() {
Fragment fragment = getFragmentManager().findFragmentByTag("yourTagForFragmentX");
if (fragment instanceof XFragment) {
// The fragment is available in the fragment manager
finish()
} else {
super.onBackPressed();
}
}
For more details, here
I think you're overcomplicating things.
Remove all of the launch mode flags for A and B - they should not be necessary.
Remove custom handling of onBackPressed - default handling should suffice.
Update A to initialize itself to the correct fragment based on the intent it's given:
For example:
onCreate(...) {
if (getIntent().getAction() == "START_ON_X") {
// Notice we REPLACE and DO NOT add to back stack
getFragmentManager().replace(fragID, createXFragment()).commit()
}
else {
getFragmentManager().replace(fragID, createDefaultFragment()).commit()
}
}
Thus, you will have:
Default launcher intent launches A.
A launches B.
B launches A with specific intent to show Fragment X
This will give you a stack of A -> B -> Ax
Then when you press back, DEFAULT BEHAVIOR will leave you on B.
Then pressing back again will leave you on A.
Then pressing back again will close your app.
Again this is all standard, default behavior. KISS.
So right now I have a situation in which I have three fragments are committed in such an order:
Fragment A -> Fragment B -> Fragment C
Then, I start an Activity from Fragment C. The issue arises when I want to pop the back stack so the user is brought to Fragment B after the activity finishes. If I attempt to pop the back stack from the Activity before calling finish(), I get an IllegalStateException, saying that the action cannot be performed after onSaveInstanceState. Thus, is it even possible to make changes to the FragmentManager responsible for the fragments from the Activity?
How does this sound myrocks2? Android: how to make an activity return results to the activity which calls it?
First activity can start a second activity and expect a result. Upon getting back a result it knows second activity did its job, and now it's required to remove fragment c. (I don't know the logic of your app, but that can work)
Someone who thinks he is so smart gave you a negative vote, but I made sure to go away. There are no dumb questions.
I have two Activities and each one has 3-4 Fragments that each replace the other one.
When Activity1,Fragment2 launches the second activity, Activity2,Fragment1 is launched and onBackPressed closes the Activity2 and goes back to Activity1 as normally.
When I'm launching Activity2 from Activity1,Fragment3 though, I want to add Fragment2 to the 2nd activity, which is done via cone in the onCreate method.
However, when the back button is pressed, the fragment disappears for a split second, leaving Activity2 blank on the screen and after that Activity2 is closed, resulting in a visual glitch.
Is there anything I can do to close Activity2 the exact moment (at least at the same visual moment) as when Fragment2 is being closed by the back button?
Thank you.
P.S.: Not adding the Fragment to the backStack seems to close the activity immediately, which is what happens in the first case (expected behavior), but when adding the Fragment to the backStack (as needed for correct operation in the second case) produces the glitch.
Ok, after fighting with the backStack for many days, I decided to skip it, since it does not seem to be working properly, or I'm not understanding it.
The way I did it is on my Activity's onBackPressed i'm checking which fragment is showing and if it's the one that should be the last one (Multiple ones are the "last one") I just finish() the Activity.
#Override
public void onBackPressed() {
MyFragment myFragment = (MyFragment)fragmentManager.findFragmentByTag("MyFragment");
if (myFragment != null && myFragment .isVisible()) {
//if myFragment is visible when the back button is pressed...
finish();
} else {
super.onBackPressed();
}
}
Don't forget to give a name to your fragment in the FragmentManager transaciton. In my case it is "MyFragment".
I have a small layout in my activity that I add Fragments to based on the User navigating through the app.
Assuming the user navigates thusly:
Activity -> Fragment A -> Fragment B -> Fragment C -> Button Click
I would like to be able to to hide the Fragments and show the blank Activity again.
This is how I'm adding the Fragments to the activity:
protected void addFragment(Fragment fragment)
{
getSupportFragmentManager().beginTransaction().replace(R.id.secondary_fragment, fragment).addToBackStack(fragment.getTitle()).commit();
}
To clear all the Fragments, I use:
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
However, is there a way to clear the fragments in a way that if the user presses back, they would be able to go back to Fragment C (as opposed to exiting the App)?
Maybe instead of pop all the backStack, you just get the fragment view by id and setVisibility to invisible?
Try starting a new instance of your Activity with a clear stack on the button press (if I'm correct in assuming this comes after C as you described). This way the First Activity instance will still have up to Fragment C and the Second Activity instance will be whatever you like (Fragment A > Fragment D > Fragment F). And you won't need to pop/clear any back stack for any Activity.
HTHs
I am having 4 (let's say 1,2,3 & 4) fragments. And at a time any one of them will be visible to User. In 2nd fragment I want to do something when user is coming on it.
Now when User navigated to 3rd fragment & hits the back button, I want to run a some code. My problem is onResume is not getting called when user hits the back button & come to 2nd fragment.
I recently bumped into the same problem, I know that its too late, but just in case some one else is looking for this, here's my answer:
Thanks #fasteque for narrowing down my search.
The fragments onResume() or onPause() will be called only when the Activities onResume() or onPause() is called. They are tightly coupled to the Activity.
But if you still want listen to the changes in your activity like which fragment is on top, and trigger events accordingly, you might wanna have a look at FragmentManager.OnBackStackChangedListener
Hope this helps :)
I've had the same problem. If you want to switch from 3rd fragment to 2nd fragment (with the back button or another way) you can call 2nd fragment in the onPause of 3rd fragment.
#Override
public void onPause() {
super.onPause();
Fragment2 fragment2= (Fragment2) getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment2);
if (fragment2!= null) {
//you can call any function from fragment2
fragment2.SomeFunctions();
}
}