Bring Fragment to top of stack - java

When adding activities to the stack, I can do something like this suggests:
How to bring an activity to foreground (top of stack)?
However, I have a Navigation Drawer that uses fragments. I add these fragments to my back stack via the below code:
FragmentTransaction transaction = activity.getFragmentManager().beginTransaction();
transaction.replace(R.id.main_fragment, new EntryFragment());
transaction.addToBackStack(activity.mTitle.toString());
transaction.commit();
The problem is, I now need to take a fragment that is already part of the back stack and bring it to the top, dropping all fragments currently above it out of the stack. Essentially what FLAG_ACTIVITY_REORDER_TO_FRONT and FLAG_ACTIVITY_CLEAR_TOP flags would do when using activities.
How do I accomplish this with fragments?

You can use the following method to return to the instance of the Fragment on the backstack:
activity.getFragmentManager().popBackStackImmediate(tag, 0);
Note, that in your FragmentTransaction you will need to define a unique tag for each Fragment you commit to the backstack and retrieve that tag to return to the fragment here.

Related

Question about BottomNavigationView in Android

I have general questions about BottomNavigationView. I would like to have a BottomNavigationView in each of my Activities in an App for ordering something (e.g. food). It should have 4 buttoms:
Back
Info
Stats
My Orders
With 'Back' the app should just go back to the previous activity. The buttoms 'Stats' and 'My Orders' should switch to a persistent activity that should not be destroyed when not being displayed. 'My Orders' should display the last orders. The buttom 'Info' should only display some information about the current item or current menu (depending from which activity it is called). So basically I have 2 questions:
Should the Activities 'Info', 'Stats', and 'My Orders' be real Activities or just Fragments? Normally I think that at leat 'Stats', and 'My Orders' should be real Activities as they are persistent. But in many BottomNavigationView only Fragments are used?
How can I pass content information to the Activity/Fragment 'Info'. This Activity/Fragment should display information based on the Activity is was called from. Let's say the Activities are different dishes. Do I have to create a separate Info-Activity/Fragment for each dish? Or can I somehow define a dynamic Activity/Fragment that displayes information based on the current Activity?
I'd appreciate every comment and I'd really appreciate your help.
The recommended approach is Single Activity and Multiple fragments.
You can do this using Jetpack's Navigation Component
In case you need to pass data from an Activity/Fragment to the new calling Fragment, it can be done by setting arguments on the calling fragment and then getting it on the called fragment. If there is something which requires to be dynamic, for example- dishes fragment, make a single fragment and common layout and load the data dynamically from the backend.
For Setting Arguments, this should help
How to pass a variable from Activity to Fragment, and pass it back?
Note: You can use fragment without using Navigation Components but you have to use FragmentManager and FragmentTransaction and also have to maintain the Backstack by yourself which could be quite complicated

Move from Activity to Fragment when button clicked

I used this code to move from Activity to Fragment when button clicked but when I run this code I find Activity is still in background.
TopicsFragment fragment = new TopicsFragment();
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.welcome_id, fragment);
transaction.commit();
First of all, you need to understand what Activity and Fragments are. You cannot move from Activity to Fragment.
You can inflate a Fragment or Fragments into an Activity. Fragments cannot be independent from an activity.
A fragment must always be hosted in an activity and the fragment's
lifecycle is directly affected by the host activity's lifecycle. For
example, when the activity is paused, so are all fragments in it, and
when the activity is destroyed, so are all fragments. However, while
an activity is running (it is in the resumed lifecycle state), you can
manipulate each fragment independently, such as add or remove them.
When you perform such a fragment transaction, you can also add it to a
back stack that's managed by the activity—each back stack entry in the
activity is a record of the fragment transaction that occurred. The
back stack allows the user to reverse a fragment transaction (navigate
backwards), by pressing the Back button.
Source: https://developer.android.com/guide/components/fragments
If you don't want to see the activity after entering into fragment, you could extend from DialogFragment and make it fullscreen, there are many examples, google it using "android fullscreen dialogfragment".
and here is DialogFragment doc.

Android - onBackPressed has no effect from fragment

I have one Activity with a viewpager in it and also a frameLayout which is used as a container for fragments that should be drawn above this viewpager.
When I click a button of my Activity a fragment is shown in that framelayout container. On a press in the navigation bar I can close this fragment. All these things work fine when called from the activity itself.
I have now the situation that on a specific action from one of the fragments in the viewpager I invoke a callback which the main activity implements and then shows a fragment in the frame layout.
But here now comes the problem. When I want to navigate back or rather want to close the fragment like I described before, nothing happens.
So in conclusion:
"Fragment show to container" invoked from Activity directly -> I can navigate back from the fragment by getActivity().onBackpressed()
"Fragment show to container" invoke from fragment in viewpager and then delegated to activity -> The navigation back or getActivity().onBackpressed() has no effect.
So my question is: How can I close the fragment in the container even when I call it from one the fragments inside the viewpager of the activity?
Probably you are adding a fragment to the backstack, so onBackPressed you should pop last fragment from the backstack.
Something like that:
FragmentManager fm = activity.getFragmentManager();
fm.popBackStackImmediate();
Meanwhile I found the problem..
Due to the fact that I am running some kind of update loop, I added the fragments multiple times to the backstack but didn't realize it because the fragment itself didn't change, the new instances just got added to the backstack. So when I called the onBackpressed() method the instances got removed from the backstack but because there were like 200 of them nothing happened.

Proper/Best Way to Handle Android Fragment Transaction Issue

In my open source Android app, an issue has been discovered where a specific fragment will come into view on top of another fragment or crash the app in a certain situation.
The issue on GitHub if you want to see more information and example screenshots:
https://github.com/rpi-mobile/RPIMobile-Android/issues/31
I have pinned down the reason, but want to know which of the methods in the android.support.v4.app package to use to resolve the issue.
In MainActivity.java, is the code for the navigation drawer that uses FragmentTransaction.replace() to switch fragments.
The issue arises because in MapFragment, I use:
ViewMapFragment vmf = new ViewMapFragment();
FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction();
ft.addToBackStack(null);
ft.replace(R.id.content_frame, vmf);
ft.commit();
And in ViewMapFragment's onDestroyView():
FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.remove(fm.findFragmentById(R.id.mapview));
ft.commit();
The onDestroyView() properly removes the ViewMapFragment from view, but if you have it in view and use the navigation drawer to change to a different fragment, MapFragment is still on the back stack.
So, for my questions:
1) How do I check if a particular fragment is on the back stack before attempting to remove/replace it, or will the app not crash if you attempt when nothing is there (i.e. not checking)? E.g. calling popBackStack() when there is nothing on the back stack.
2) Should I use FragmentManager class methods to attempt to remove the MapFragment from the back stack or should I use FragmentTransaction methods? Pros vs cons?
3) What is the difference in the UI between popBackStack() and popBackStackImmediate()? Does the user see some glitchy transitions?
According to the documentation of FragmentTransaction, when you invoke addToBackStack method it just remembers what actions you perform in that transaction. When popBackStack method is invoked it will reverse those actions and execute them.
So, what happens:
When we go from MapFragment to ViewMapFragment, FragmentManager remembers removing MapFragment and adding ViewMapFragment operations.
Then we go to any other fragment using Navigation Drawer, which causes ViewMapFragment removing operation, and after that it adds fragment selected from Drawer.
Finally, when we press Back button, popBackStackImmediate is invoked and FragmentManager executes reversed operations: ViewMapFragment is removed (actually it is removed already) and MapFragment is added. And here is the problem occurs - the selected fragment is still there, so we have two fragments on the screen at the same time.
There is several options to handle such a situation:
Simply add Navigation Drawer operations to back stack.
Clear back stack every time when fragment switching is started by Navigation Drawer.
To clear back stack you can use this code (related question):
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
If you put this line in the beginning of your selectItem method the bug will be fixed.
And your questions:
You can check whether a fragment is in a back stack by using FragmentManager.findFragmentByTag method. See example in the end of my answer.
An entry of back stack technically can contain several fragments, and I don't think there is a way to remove single fragment from it. Instead of removing you can just clear back stack (please, refer this question).
The main difference is that popBackStack will give you a chance to do something, before it actually starts popping process (it will be started when application returns to it's event loop).
Example. For instance, we have added a fragment with tag "fragment-1":
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame, new TestFragment(), "fragment-1")
.commit();
Then, we put it into a back stack and replace it with another fragment:
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.frame, new TestFragment(), "another-fragment")
.commit();
At this point getSupportFragmentManager().findFragmentByTag("fragment-1") returns our first fragment (it gets it from a back stack entry). Now we can check whether this fragment is added to its activity by isAdded method - if it returns false, then we can make an assumption that the fragment is in a back stack.

Add current fragment to backstack: Android

I am adding a fragment in an activity, fragment A.
Now from this fragment, I go to various other fragments, and whenever I go to those, I replace fragment A.
But there is only one scenario when i want that when i am about to go from fragment A to fragment Z, I add fragment A to the back stack.
So basically for all the clicks on fragment A, which take the user to other fragments (by replacing fragment A), there is only click where I want that fragment A be put in the back stack, this i want as when i press back from this new fragment Z, I do not want the activity to finish, rather i want fragment A to just come back up.
Now one dirty way of doing this is to do the following:
#Override
public void onBackPressed() {
if ( getFragmentManager().findFragmentByTag(FragmentZ.class.toString()) == null){
super.onBackPressed();
}
else {
//i would add fragment A over here.
}
}
But I was thinking that if i could add fragment A into the back stack just before i go to fragment Z then i do not have to take care of the above.
Could some please help me with the above?
The only way you can add Fragment A to the back stack is before you commit the transaction which replaces Fragment A with Fragment Z.
You can not add it later on after Fragment Z is already added.
Before calling commit() on the transaction which inserts Fragment Z, call addToBackStack(null) on the the transaction.
Then you will not have to override onBackPressed().

Categories