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 :)
Related
I have created an AppCompatActivity Opened fragment A->B->C->D->E->F
with replace()
I am on F which contain button when I press the
button I want to clear Fragments up to C and Want to open G on top of C so new Sequence will be A->B->C->G.I can do this with
popBackStackImmediate() and add G on top of C with replace function.
Problem: When I press the button I see C for fraction of seconds and then G Is displayed on it.To Prevent this I tried to stop the animations with help of answer but C still visible for fraction of seconds even when the animation is stopped for fragments.
Is there any better way we can design fragment flow or way to solve this flicks when replacing fragment on top of C?
I was so curious about this question that i created a sample project and implemented the same use-case that you mentioned in your question. Here is how i handled this.
Used this method to remove F,E,D fragments from backstack
private void removeFragments() {
getSupportFragmentManager().popBackStack("F", FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().popBackStack("E", FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().popBackStack("D", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
Used this method to replace fragment
private void replaceNewFragment(String key) {
getSupportFragmentManager().beginTransaction().addToBackStack(key)
.replace(android.R.id.content, AFragment.newInstance(key)).commit();
}
Here is a video demo video.
Here is complete of this project on github
More Generic Solution for such navigation flow, Replace fragment like this
getSupportFragmentManager().beginTransaction().
replace(R.id.f_container,new FragmentA())
.addToBackStack("A")
.commit();
getSupportFragmentManager().beginTransaction().
replace(R.id.f_container,new FragmentB())
.addToBackStack("B")
.commit();
like wise do it till fragment F and lets assume you have submit button on F
now inside onClick of submit button
Pop back stack till D with POP_BACK_STACK_INCLUSIVE flag like below and Add replace container with fragment G
getActivity().getSupportFragmentManager().popBackStack("D",
FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().
replace(R.id.f_container,new FragmentG())
.addToBackStack("G")
.commit();
Now when you press back button you will see Fragment C
I hope this will help you, its working for me
I'm so very confused and have been reading on this topic for a while.
I have a MainActivity that has multiple possible contents (switched between via navigation drawer), which I've set via multiple fragments (lets call them Fragment1, Fragment2 and Fragment3).
That works fine.
One of my fragments, Fragment3, is a View that can segue to a new activity, View2.
View2 has a back button. When I press on the View2 back button I want to see Fragment3 on my MainActivity, not Fragment1, which is what I currently get. This is because OnCreate, by default, loads Fragment1.
What is the best way to do this?
Thanks so much in advance! (vent: iOS makes this so much easier).
The official documentation for Fragments states that you should make sure to call addToBackStack() before commiting your fragment transaction on your first activity holding the 3 fragments.
In order to go back to the last used fragment from the second activity , you should override the onBackPressed() method in this activity :
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
The documentation is very complete on the subject : Read it here
Update:
I just added this to the back button code:
finish();
return true;
I had to do it within onOptionsItemSelected(MenuItem item)... for some reason onBackPressed is not fired.
I have an app with a main activity which loads a navigation drawer, and a pair of fragments that load in that activity ...
In the navigation drawer I have 4 options A, B, C and D ... the first one loads FragmentA on my activity and the last 3 load FragmentB ..
FragmentA displays a list of elements and, upon selecting one of these elements FragmentB is used to load its content... I want to change the home (hamburger/drawer) icon on FragmentB for the up icon when initiating from FragmentA (and change the corresponding behavior to make a popstack on select).. I have no problem with this using setDisplayHomeAsUpEnabled(true), but since all this is occurring inside one activity if I then select one other option (say B) from the navigation drawer the up icon will still be showing (it its also showing on the popped fragment)...
if I use setDisplayHomeAsUpEnabled(false) all this do is hide the home/up button from the toolbar, I need to recover the home button and make sure this will be shown when FragmentB is initiated from the drawer menu ...
Does this problem ring a bell to anyone? or am I just using fragments the wrong way? .. any advice will be appreciated
EDIT
this is more or less what I have in code
In Main Activity .. as the onNavigationItemSelected(MenuItem item) for the drawer I have a something like this ...
switch(optionNumber) {
case 0:
fragment = FragmentA.newInstance(optionNumber);
break;
default:
fragment = FragmentB.newInstance(optionNumber);
break;
}
Fragment frag = fragmentManager.findFragmentByTag("current_fragment");
if (frag != null && frag.getClass() == FolderFragment.class){
((FolderFragment)frag).resetScroll();
}
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction().replace(R.id.content, fragment, "current_fragment").commit();
which selects the fragment to load according to the option selected..
In FragmentA I'm calling FragmentB with this ..
FragmentB fFragment = FragmentB.newInstance(position);
Bundle args = new Bundle();
args.putString("filter", "something"); fFragment.setArguments(args);
mActivity.getSupportFragmentManager().beginTransaction()
.replace(R.id.flContent, fFragment, "current_fragment")
.addToBackStack(null)
.commit();
Preserving the fragment in the stack
And in fragmentB inside onResume() function I got something like...
String filter = getArguments().getString("filter", null);
if (type != null) {
mActivity.setTitle(title);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
}else {
/*mActivity.getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
mActivity.getSupportActionBar().setHomeButtonEnabled(true);
mActivity.getSupportActionBar().setIcon(R.mipmap.ic_menu);*/
}
So When I'm creating fragmentB I check for arguments and see if it comes from fragmentA or not ( I could also check the fragmentmanager backstack and see if there's something)... there I just change the drawer icon with setDisplayShowHomeEnabled(true) ... leaving the back arrow, if I return to FragmentA (via onBackPressed()) FragmentA shows the arrow and I need it to show the original drawer icon ... the same happens if I select an option from the drawer menu ...
Does this gives more clarity to my issue ?... I have some commented code there because it doesn't work .. if I activate the line with setDisplayHomeAsUpEnabled(false).. the icon just disappears from the activity (which is the intended result of the function as far as I know)...
After a while I finally found this post
Switching between Android Navigation Drawer image and Up caret when using fragments
I guess that when involving a Drawer in the interface you might need to handle this issue with that component... this post gave me the answer.
Particular notice to the last comment by Wolfram Rittmeyer
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
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.