When I press a button, my app creates a fragment. I'd like to make sure that only one of this fragment is created, e.g. disable the button if the fragment already exists.
How do I check that it creates only one fragment? Is it possible to get a Fragment count or is there some option that limits it to creating only one?
You can use the methods that sandrstar mentioned. When attaching a fragment u can first check to see if its already attached.
For example if you are adding the fragment dynamically you can stop the fragment from being re-added by doing the following:
MyFragment myFragment = getFragmentManager().findFragmentByTag("MyFragmentTag")
if(myFragment == null)
{
myFragment = MyFragment.newInstance();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.layout.mylayout,myFragment,"MyFragmentTag");
ft.commit();
}
Related
I've done some research but I really couldn't find the answer.
I have single activity with side menu, and holder. I have many (non support) fragments, and all of them are using same holder (one at a time).
When user uses menu (it's in main activity), and goes another page, I want to add name of the current fragment to backstack (using .addToBackStack(Fragment1.class.getName())), but I couldn't find how to get current fragment.
I don't want to implement interface etc to keep track of current fragment. There is a super simple way using fragmentManger isn't there?
You can get your current fragment like this:
if (getFragmentManager().getBackStackEntryCount() > 1) {
Fragment f = getFragmentManager().findFragmentById(R.id.content_frame);
if (f instanceof BlankFragment) {
// Do something
}
}
OK,
If you want to get latest entry from backstack(thanks to #AndroidGeek);
fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-1);
and, if you want to get currently active fragment (thanks to #Salman500 #AndroidGeek);
Fragment f = getFragmentManager().findFragmentById(R.id.fragment_holder);
you can use this to get fragment id for non support fragment
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_id);
if(fragment!=null)
{
getFragmentManager()
.beginTransaction()
.addToBackStack(null)
.commit();
}
You can keep track of fragments in the main activity (with variables) and access them there. Example:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction= manager.beginTransaction();
MyFragment myFragment = new MyFragment();
myFragment.doSomething();
Adding to the back-stack:
FragmentTransaction fragment = getSupportFragmentManager().beginTransaction();
fragment.addToBackStack(fragment);
fragment.commit();
This is answered here: get currently displayed fragment
Just use addToBackStack() before you commit() the fragment trancsaction. See it here
So your code will look like :
...
fragmentTransaction.replace(R.id.holder, newFragmentToShow, newFragmentTag);
fragmentTransaction.addToBackStack();
fragmentTransaction.commit();
...
EDIT : after OP was edited
You do not need the fragment class to call addToBackStack() as you have mentioned in the OP. The String argument is an optional string just to keep the state for the backstack state. You should see the documentation
It is all internally managed and the current active fragment is automatically added to the backStack, you may call it from where ever you want, it will always use current active fragment.
Guys i searched a lot but didn't got. I have two fragment
1) Form Transaction
2) Form Transaction statusin Form Transaction there are some fields to fill information and submit button. On Clicking submit i need to browse a file (which is on another activity but same fragment i.e Form Transaction). How can it be possible to have two activities on same fragment
Do i need to create another activity? And to whom will it extend?
first fragment with personal information
A Fragment belongs to a host Activity and not the other way round. An Activity can host multiple Fragments.
Reads the docs for more info:
https://developer.android.com/guide/components/fragments.html
In your case what it seems you are trying to achieve is to replace Form Transaction Fragment with a different layout and logic. You can replace it with another new Fragment itself.
Use a FragmentManager to replace the existing Fragment:
FragmentManager fm = getFragmentManager();
if (fm != null) {
// Perform the FragmentTransaction to replace the Form Transaction content.
// Using FragmentTransaction#replace will destroy any Fragments
// currently inside R.id.fragment_content and add the new Fragment
// in its place.
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_content, new YourFragment());
ft.commit();
}
Change R.id.fragment_content to your Form Transaction Fragment's placeholder and YourFragment to your newly created Fragment.
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'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'm trying to decide and show a fragment in activity's onResume method, but in case a previously added fragment is chosen again, then the activity goes blank.
Sample code (with one fragment):
#Override
protected void onResume(){
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.myLayout, fragA);
trans.commit();
getSupportFragmentManager().executePendingTransactions();
}
With above code, when the activity is created for the first time, it shows fragA correctly, but in case I press Home Key and then switch back to my activity (in order to provoke onResume again), it all goes blank (seems like fragA is removed).
Is replacing a previously added fragment removes itself? or how not to loose a fragment if it is replaced by itself?
You can't replace a fragment with itself. The first half of a replace is a removal of the previous fragment at that id. Once a fragment is removed it can no longer be added or used by the fragment manager (so the add portion of the replace will not work properly).
Depending on your use case, you have two options:
Create a new fragment instead of reusing the existing instance
Use some other method to see if its necessary to replace your fragment
Finally, you probably don't need to call executePendingTransactions.
You can try:
if( !(getSupportFragmentManager().findFragmentById(R.id.myLayout) instanceof FragmentA) ) {
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.myLayout, fragA);
trans.commit();
}
And I assume that fragA is FragmentA class object.
Finally, I had to put a check before replacing fragments. In case, an (already added) fragment is requested for replace again, I had to check if its already added then ignore the replacement, else proceed. For example:
#Override
protected void onResume() {
if (!fragA.isAdded()) {
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.myLayout, fragA);
trans.commit();
//getSupportFragmentManager().executePendingTransactions(); //unnecessary
}
}
When referencing back to a created Fragment please do make sure to try adding the
fragmentTransaction.addToBackStack(null);
method right before committing so that your Fragment is resumed instead of destroyed as mentioned in the developer guides.
If you don't call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and is later resumed if the user navigates back.
You can find this at the end of this page.