I'm working on an inherited Android project that makes use of fragments. The mainactivity has a side menu drawer that allows the user to tap on a list of items, each of which opens a new fragment in another file.
Right now, pressing the back button closes the app abruptly. I wish for the back button to work such that it will bring the user back to the previously viewed fragment, and when the user is at the very first viewed fragment, pressing a back button will bring an app exit confirmation box.
I understand that I should be using addToBackStack() but I'm not sure how to implement it in my code.
Here's the code originally in mainactivity when an item is selected:
FragmentManager fm = getFragmentManager();
switch (position) {
case 0:
if (fragmentManager.findFragmentById(R.id.content_frame != null) {
Fragment currentFragment = fragmentManager.findFragmentById(R.id.content_frame);
fm.befineTransaction().remove(currentFragment).commit();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
Item0 item1Fragment = new Item0();
fm.beginTransaction().replace(R.id.content_frame, item0Fragment).commit();
break;
case 1 onwards are identical, except Item0/item0Fragment references are replaced with their respective values.
I'm very new to fragments, but from what I can see, the code is first detecting if the activity has a frame for the fragment, and if so, it removes the current fragment, and completely clears the fragment back stack. It then creates a new fragment, and replaces the current fragment with the new one.
Here's my code currently after some changes, and it seems to work, except for a few problems which I'll describe after the code:
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
switch (position) {
case 0:
Item0 item1Fragment = new Item0();
ft.replace(R.id.content_frame, item0Fragment).addToBackStack(null).commit();
break;
The above modified code provides correct navigation, except:
When the I've gone back to the very first fragment, then a back button press removes that fragment and presents an empty fragment on screen, and the next back button press will close the app. The desired behavior would be that a back button press on the very first fragment will bring out a confirmation button to close the app.
When the items on the side menu are tapped and selected, I call mItemList.setItemChecked(position). How do I call update this when the back button is tapped so that the previous selection is selected?
Does anyone know how to make this work?
Thanks.
Have you checked the developer.android ? Here is how they explain.
http://developer.android.com/training/implementing-navigation/temporal.html#back-fragments
Related
I am new to android development, please bear with me.
I have three fragments - Frag1, Frag2 and Frag3.
Frag1 is a sort of ListView having a list of items which is created when the App is launched.
Frag2 and Frag3 basically correspond to VideoViews which will be used to play different videos from different players. One of them will play the content Video and the other will play Ad video.
When I click on a particular item in Frag1, I want to create both Frag2 and Frag3. I want to have both fragments since I might have to play the Ad at any time. I will hide the content Fragment when Ad is playing and Vice versa.
Also I want that when back button is pressed, I should go back to Frag1 ( the listView), irrespective of whether Frag2 or Frag3 was visible when back button was pressed.
What I am not able to clearly figure out is how to stack the fragments so that whenever I press back button while playing either an Ad or video, it goes to the listView. Because if i understand correctly, the fragments get stacked up in the order they are added. So if I add in the order Frag1 followed by Frag2 and Frag3, then pressing back when Frag3 is on top will go to Frag2 rather than Frag1. Also say if currently Frag2 is visible and I press back, then I think Frag3 will still remain even though I want both Frag2 and Frag3 to get popped whenever I press back button.
Please help me regarding this. Any links which properly explains the concepts used here will also be appreciated.
For this purpose you can use to tab fragment with below functionality.
Try this one-
public void onBackPressed(){
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack();
}
Fragments only get added to back stack if you call addToBackStack() while performing the Fragment Transaction.
Method 1
So while opening Frag2 from Frag1 you should call that because you want your Frag1 to be there when you press back.
Whereas when you open Frag3 from Frag2 or vice-versa, then don't call addToBackStack(). If then you press the back button from Frag3 or Frag2, you'll directly go to Frag1 as your back stack will only have Frag1.
Method 2
Another way is to override your onBackPressed() method in Activity. With this whenever the back button is pressed, you can pop the back stack using
Fragment f = getFragmentManager.popBackStackImmediate
And then check which Fragment is that by -
if(f instanceof Frag2 || f instanceof Frag3){
//pop it
}
Now check again. Keep checking till only Frag1 is left.
you need to manage the fragment by giving id to it , you can replace remove whatever you want in on backpress() , just look out the code that i develop to manage , me too had bit similar requirement so this is how i managed
#Override
public void onBackPressed() {
Highlights_fragment test1 = (Highlights_fragment)getFragmentManager().findFragmentByTag("1");
Aktulless_Fragment test2 = (Aktulless_Fragment)getFragmentManager().findFragmentByTag("2");
if (test1 != null && test1.isVisible()) {
//DO STUFF
getFragmentManager().beginTransaction().remove(getFragmentManager().findFragmentById(R.id.frame_container)).commit();
}
else if(test2 != null && test2.isVisible()){
//Whatever
getFragmentManager().beginTransaction().remove(getFragmentManager().findFragmentById(R.id.frame_container)).commit();
}
else
{
super.onBackPressed();
}
and for Frag2 and Frag3 you need to replace the particular fragment on particular item pressed.
Hope it helps :)
My Application has one Activity with a layout (FrameLayout) for many fragments.
At the start of the Application it displays a list of Places (PlacesFragment).
When a Place is clicked, a Fragment that displays a list of cams (CamFragment) is added. Inside this fragment there is also a button "info".
When the user press the "info" button a new fragment (InfoPlaceFragment) that displays information about the place, is added.
Here is a graphical explanation:
I want to be able to go back to "CamFragment(B)" from "InfoPlaceFragment(C)", and to go back to "PlacesFragment(A)" from "CamFragment(B)".
One Question:
1) Is it possible to realize this or an alternative solution is better?
------- EDIT -------
SOLUTION:
In the "MainActivity.java":
onPlaceParse() // This method is called when the data from the server is received:
// Here I create the "PlaceFragment"
fManager = getSupportFragmentManager();
fragmentPlaces = new PlacesFragment();
fManager.beginTransaction()
.replace(R.id.fragment_list_container, fragmentPlaces)
.commit();
onResortSelected // This method is called when the resort is selected
fragmentCams = new CamsFragment();
fManager.beginTransaction()
.replace(R.id.fragment_list_container, fragmentCams)
.addToBackStack(null)
.commit();
onButtonInfoSelected // This method is called when the btn info is selected
fragmentInfo = new InfoResortFragment();
fManager = getSupportFragmentManager();
fManager.beginTransaction()
.replace(R.id.fragment_list_container, fragmentInfo, "Info")
.addToBackStack(null)
.commit();
When you press the back button, if you are in the "Info Fragment" it returns to "PlaceFragment" and if you are in the "CamsFragment" it returns to "PlacesFragment".
This is possible, you need to call addToBackStack(null) in the fragment transactions.
Reference: Providing Proper Back Navigation
When you create your FragmentTransaction that will add/remove/replace (or whatever pattern you are using) the Fragments, just make sure to call addToBackStack(). Then, when the user presses the back button, the system will automatically cycle back through the entries added to the back stack, in reverse order from how they were originally added. No additional work is required on your part! :)
In my application I have two fragments A and B. A fragment contains Google map and listview inside on it B fragment Google map only.
I want open B fragment from A fragment but when I press back button it has to go to A fragment without loading data.
public void addPage(final DefaultFragment pDefaultFragment, final boolean isAddToBackStack){
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.add(R.id.content_frame, pDefaultFragment);
//transaction.replace(R.id.content_frame, pDefaultFragment);
if (isAddToBackStack) transaction.addToBackStack(null);
transaction.commitAllowingStateLoss();
}
I use this code for adding fragment
Bframent b = new Bfragment();
addPage(b,true);
I know differences between transaction. add and transaction.replace. My problem is when I use transaction.add A fragment's map doesn't destroy it stays above of B fragment's map when pressing button. But when use transaction.replace after press back button data loads again.
So could anyone tell me what should I do to Press back button without to load data without any problem on view also.
On back press just provide your fragment null;
Activity 1 is visible. Press a button, and Activity 2 opens.
Activity 2 adds fragment A to itself (and back stack) and it displays fine
Pressing a button within the fragment transitions to another fragment, B
Press Back. Nothing happens. Huh? The Back press is seemingly absorbed and not acted upon, the display remains the same.
Press Back a second time, it reverts to the Activity 1, as expected.
Why is my fragment not being shown in step 4? I've added the fragment to the back stack, so why (when the Back button seems aware of its existence) does it not show the fragment?
Here's the code I'm using in Activity 2 to open Fragment A.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_profile_edit);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
transaction.addToBackStack(null);
transaction.add(android.R.id.content, new MyFragment());
transaction.commit();
}
And here's the code to open Fragment B
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
transaction.add(android.R.id.content, new MyOtherFragment());
transaction.commit();
Have you tried transaction.replace(...) instead of transaction.add(...)? That should work. I'm guessing because if you're just adding a fragment over another, it doesn't see transaction as wanting to go back fro Fragment A.
EDIT
The actual answer for the question is below in the comments: addToBackStack() should be used on the fragment which is replacing, not the one being replaced.
I created a sample app to test this overlapping issue.
I have a fragment type, Fragment1, and I create a new instance of Fragment1 and add it to a FrameLayout in my activity at runtime. I add the fragment with the help of a few buttons.
Note: I have given each new instance of Fragment1 a different number(#1, #2, #3, etc.) to display on the UI to help me figure out which fragment I am viewing.
So.. here is what I do:
Click on Button 3, create new instance of Fragment1 and add it to Frame1.
Click on Button 4, create new instance of Fragment1 and add it to Frame1 and add it to the fragment backstack.
Repeat 1 and 2.
Repeat 1 and 2.
Now, I have fragments in this order: 1(#1),2(#2),1(#3),2(#4),1(#5),2(#6).
I press the back key when viewing fragment #6.
Back key press, UI displays (#5).
Back key press, UI displays (#3 AND #5),
Back key press, UI displays (#1, #3, AND #5)
It seems fragments are getting displayed ON TOP of each other.
WHY? Is there an overlapping issue? How can I clear out this overlapping issue. I thought this would be an issue on the compatibility library... but it is also on 3.0.
Code for adding fragments:
public int doFragmentChange(int cont1, Fragment frag1, String tag1, int cont2, Fragment frag2, String tag2,
boolean addToStack, String stackTag) {
FragmentManager fm = getFragmentManager();// getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (frag1 != null) {
ft.replace(cont1, frag1, tag1);
}
if (frag2 != null) {
ft.replace(cont2, frag2, tag2);
}
// add fragment to stack
if (addToStack)
ft.addToBackStack(stackTag);
return ft.commit();
}
If you perform two add calls one after the other (two commit calls) then yes the fragments will appear overlaid, one on top of the other effectively.
So (for new example) if say you replace frag1 with frag2 and then frag3 with frag4 in the same frame with no backstack transaction then I would expect frag2 and frag4 to be overlaid.
Furtheremore there is also a potential issue in your chaining of replace. You should call a separate commit for each. See Android — Replace Fragment Back Stack With New Stack?.
Just override the onBackPress() or onKeyUp and remove the top fragment.