I have a situation in which I need to show/hide a fragment based on a dynamic variable. My question is should I create the fragment once, and then show/hide based on the variable. Or should I destroy/create it each time?
Create the fragment
Fragment alertFragment = new AlertFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(android.R.id.content, alertFragment).commit();
After this should I call show/hide each time?
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.show(alertFragment) // or hide
.commit();
Seems like a lot of work to show/hide something each time. Is this the right way to do it?
I'd say that depends on weather it matters for your application if your Fragment is destroyed or not.
If it doesn't matter at all, simply replace the Fragment everytime by a new one. This is the simplest solution and does not require any logic.
Fragment f = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content, f).commit();
Related
Working with fragments I've always used replace() for my transactions, but I wish I didn't have to save instance states anymore to restore a fragment's view and prevent reloading when coming back to that fragment. So, I've decided to work with add(). The thing is when I add another fragment, the previous fragment view remains in the background and that's fine (that's the behavior I expected), but the problem is I can actually interact with the views in the background. Example:
Fragment A has a Button
Fragment B has a TextView
When I add Fragment A and later add Fragment B, I'm able to click on Fragment A's Button, even staying on Fragment B's view.
I'm using:
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction().
add(getRootViewContainer(),fragment,fragment.getClass().getSimpleName());
if (shouldGoBack)
fragmentTransaction.addToBackStack(fragment.getClass().getSimpleName());
where getRootViewContainer() returns the id of the FrameLayout I'm using as my activity main container.
Now, is it really the default behavior of add()?
If so, is there a proper way to avoid this or one just has to use replace()?
What you can do here is just hide previous fragment at the time of transaction of current fragment.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment newFragment= new MyFragment ();
ft.hide(CurrentFragment.this);
ft.show(newFragment);
ft.commit();
It worked for me just try it.
FragmentTransaction.hide(fragmentBehind); //works for me!
example :
//I have it globally available
FragmentTransaction trans = MainActivity.getManager().beginTransaction();
//not globally
FragmentTransaction trans = getFragmentManager().beginTransaction();
MapFragment newFragment = new newFragment();
trans.add(R.id.fragmentContainer, newFragment, tag);
trans.hide(this);
trans.addToBackStack(tag);
trans.commit();
Yes, this is a default behaviour of add().
If you really don't want to user replace(), you can try to disable views which are inside "old" fragment.
I am looking for a better approach here. What you suggest if i have 10+ fragments on a navigation drawer.
FragmentManager fragmentManager = getSupportFragmentManager ();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();
Using singleton pattern to get the instance of a fragment and add just once to fragmentTransaction if it's not added.
fragmentTransaction.add (R.id.testLayoutContent, fragment);
Or the another approach which initialize fragment each time and replace the fragment.
NOTE: Each fragments have customize components, live map etc.
I'm having some troubles with my Fragments management..
It's quite new for me and I'm pretty sure you'll find an easy way to solve my problem.
So I have a NavigationDrawer in a FragmentActivity and from this, I can navigate between two fragments.
One of those two fragments has children in a ViewPager.
I'd like to change the Parent Fragment from a ChildFragment which is in the ViewPager..
With my friend Paint, I drew my problem
http://goo.gl/OGdf1c
So as you can see, I'd like to load FragmentA from Fragment2B
Thank you !
Just perform a normal FragmentTransaction and be sure to use the FragmentManager of the Activity!
FragmentManager manager = getActivity().getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(...);
transaction.commit();
If your Activity is a FragmentActivity or ActionBarActivity you have to remember to use the support FragmentManager, aside from that everything stays the same:
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(...);
transaction.commit();
I've setup a new Android project that comes with an activity. Here's the boiler plate code:
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
Can someone explain what this is doing exactly? From what I can see, it checks if the activity hasn't been initliazed and then inflates the layout. But what I don't understand is beginTransaction(), ew PlaceholderFragment(), and commit()
Thanks.
You use fragment transactions to add / replace (etc) fragments within a FrameLayout (R.id.container) and new PlaceholderFragment is a new instance of a fragment to be put into the container
//Check whether we're recreating a previously destroyed instance
if (savedInstanceState == null) {
//Execute a transaction, replacing any existing fragment with this one inside the frame.
//Getting FragmentManager object which will control fragment acvitiy
FragmentManager fm = getFragmentManager()
//Starting a FragmentTransaction which will handle transaction to this fragment activity
FragmentTransaction ft = fragmentManager.beginTransaction();
//Add a fragment to the activity state. This fragment may optionally also have its view (if Fragment.onCreateView returns non-null) into a container view of the activity.
ft.add(R.id.container, new PlaceholderFragment());
//Schedules a commit of this transaction.
ft.commit();
}
There is a good explanation to fragment activity here, here and here
FragmentManager is a class which helps in managing the fragments that an activity may need. So here you are basically getting an instance of it and you are beginning a transaction. You need an instance of transaction because it lets the runtime know that some change is going to happen when this is called. Here 'add()' is that change and finally you commit it to save that change.
The arguments to add are the layout where the fragment needs to be added and the PlaceHolderFragment() is the name of the Fragment you need to put in.
As fragments are the way to go, replacing all of many heavy Activites, Eclipse has also adapted to this change which cause the boiler alert. :)
Starting a fragment (which cant be done via Intents) is treated as a transaction just like in database (not a good example i guess).
getFragmentManager() - gets the Activities FragmentManger which is responsible to initiate FragmentTransaction.
beginTransaction() - creates a new Transaction for this particular fragment job.
new PlaceholderFragment() - is an instance of the PlaceholderFragment which you can find if scroll more in the Activity.
commit - a way to commit this trasaction and bring it to effect.
See Android docs. for more details. :)
It is simple my friend.
In simple Coding Language:
if (savedInstanceState == null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.tab5, new PlaceholderFragment());
fragmentTransaction.commit();
}
If you think that it explain everything, then it is a pleasure for me. Otherwise just ping me to add theory information.
I have an activity with a FrameLayout in it.
The activity should show four steps, and each step is a Fragment. When I want to go back-further, I don't want my fragments to be recreated. I would like to retain them and simply replace their view in my fragment.
I used to first create my Fragments and add them in the backstack like this:
Fragment step= new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.addToBackStack(null);
ft.commit();
notice that I don't show it, I simply create it and add to the backstack.
So, once I need one of my fragments to show, I add it (in this example I don't remove any fragment from the framelayout just because it's my first add):
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(R.id.my_frameLayout, step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
So: the problem is that I obtain a
Caused by: java.lang.IllegalStateException: Fragment already added: Frag1ActCompleteFragsCommTrack{410dcb20 #0 id=0x7f050041 -1}
But I think I can't add directly into my framelayout the first time, otherwise the next time I replace it, I could lose my fragment. Am I right? So.. what's the best practice for retaining fragments that could interchange each other in a framelayout?
Ladies and gentlemen, I did it!
If you add a Fragment, and you want it to be shown in a framelayout, remember to put it in the Fragment backstack. That's it! If you replace it in the framelayout with another one, no worries: you can put it back by finding it thanks to its tag.
It was easier than I thought actually
//step is an int describing the step associated to the fragment I wanna place
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.replace(R.id.act_complete_track_frameLayout, f, ""+step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if(firstAttach)
ft.addToBackStack(null);
ft.commit();
imagine a fragment with tag "1" replaced through the code above by a fragment with tag "2". If I want to go back to step1, I reuse that code by obtaining my old fragment with getSupportFragmentManager().findFragmentByTag("1")
To be short, I thought that FragmentTransaction.replace removed the fragment from the backstack as well. That seems not to be the case (luckily)
You can always do something like fragmentManager.putFragment(yourFragment);
If I understand correctly, you are trying to add all the fragments but not show them until you are ready. FragmentTransaction.add() doesn't exactly do that though. It will also be shown after its added. You should use hide() after adding each fragment, and then later you can use show() to make it visible, and hide() again to make other fragments invisible.
Like this:
Fragment step = new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.hide(step);
ft.commit();
Then later:
Fragment step = getSupportFragmentManager().findFragmentByTag(""+onStepNr);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.show(step);
// may want to hide other fragments here
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();