So I have started fragment A from my main activity and that fragment contains a button. When that button is clicked this code runs :
Fragment newFragment = new HomeFragment();
// consider using Java coding conventions (upper first char class names!!!)
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.formFragment_Container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
So, as you can tell, I fire up fragment B from fragment A and what I don't get is what activity hosts that fragment B, since there is no indication of main activity in this code above, nor there is indication of fragment B in main activity. Could you clarify this for me. Thanks !
When you call to
getFragmentManager()
It use instance of FragmentManager that the Activity use to manage it Fragments. So the Activity will be the same as Activity A.
It comes under the concept of nested fragments in Android. For both Fragment A and B, its associated activity is main activity(from which you have added Fragment A).
You can access Main activity and Fragment A from Fragment B.
For example. getActivity() will return Main Activity, getParentFragment() will return Fragment A.
Related
I'm having problem with fragment. Lets try to understand my issue, I have two fragment A and B. When app start with main activity,i start fragment A as you can see :
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new MusicFragment())
.commit();
When i click on a button, it starts fragment B
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
Main problem is after starting fragment B,when i pressed back to go back to fragment A , Fragment A Recreated with new state.
I don' want to recreate fragment A. I only want to start fragment from old state where i left. How to fix it ?
Instead of calling the replace method you should be calling the add method with a subsequent call to addToBackStack with an argument of null. The add method adds the fragement to the stack with a null tag and calling the addToBackStack with an argument of null then the current fragment is stopped upon commit. If the method is not called then the current fragment is destroyed and recreated when coming back.
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
You can clearly find it in the documentation quote saying this:
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.
Here are some points that need to be taken care while creating fragments.
Check the backstack if the fragment is already created.
If it was created previously pop it from the backstack and put it on top so that it is visible to the user.
If fragment is not present in backstack crate it and store it in backstack.
Create a method like below which will handle such situation.
private void openFragment(Fragment fragment_to_be_opened){
String fragment_to_be_opened_name = fragment_to_be_opened.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
// fetching the fragment if it is present in backstack
boolean fragment_allready_present = manager.popBackStackImmediate (fragment_to_be_opened_name, 0);
if (!fragment_allready_present){ //fragment is not present in backstack so create it and save the name in //backstack
FragmentTransaction fragment_trasition = manager.beginTransaction();
fragment_trasition.replace(R.id.fragment_container, fragment_to_be_opened);
fragment_trasition.addToBackStack(fragment_to_be_opened_name);
fragment_trasition.commit();
}
}
Now call this method from the activity to open a new fragment like
// create instance of fragment and pass it to the open fragment method
Fragment myFragment = new myFragment();
openFragment(myFragment);
I'm using multiple fragments inside an activity like this flow: Fragment A has a list on it's item click Fragment B opens and it also has a list opens Fragment C which has a list Open another Activity , The problem is when I go back from the other Activity I found Fragment A is opened, How I restore the last Fragment C when go back from the other activity?
here is the code of replacing Fragment inside my activity
protected void showFragment(Fragment fragment) {
String TAG = fragment.getClass().getSimpleName();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container_home, fragment, TAG);
fragmentTransaction.addToBackStack(TAG);
fragmentTransaction.commit();
}
replace removes the existing fragment and adds a new fragment. This means when you press back button the fragment that got replaced will be created with its onCreateView being invoked. Whereas add retains the existing fragments and adds a new fragment that means existing fragment will be active.
Use add instead of replace
fragmentTransaction.add(R.id.container_home, fragment, TAG);
I had the same issue solved using the above code.
You can use
fragmentTransaction.addToBackStack(null);
instead of,
fragmentTransaction.addToBackStack(TAG);
Hope Your problem will solve.
My App has only one activity and lots of fragments.
In my activty's XML, I just have a FrameLayout on which I replace/add/hide/show various fragments.
Imagine Fragment A is the first fragment the user sees when they open the app.
Click something in Fragment A to launch Fragment B and click something in Fragment B to launch Fragment C.
So the navigation is can be illustrated as follows :
Fragment A --> Fragment B --> Fragment C
I want to launch the app and show Fragment C directly from notification.
However, how can I provide back navigation from Fragment C, as such clicking back would go to Fragment B and clicking back again go to Fragment A ?
i.e How can I inject the following stack structure ?
Fragment A <-- Fragment B <-- Fragment C
Yes, you can do this. Since support library v26 you can build the stack with fragments without significant cost.
In your activity make the following:
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new FragmentA())
.addToBackStack("fragmentA")
.setReorderingAllowed(true)
.commit();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new FragmentB())
.addToBackStack("fragmentB")
.setReorderingAllowed(true)
.commit();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new FragmentC())
.addToBackStack("fragmentC")
.setReorderingAllowed(true)
.commit();
Keep in mind that FragmentA and FragmentB will behave in a bit different way after pressing back on FragmentC due to setReorderingAllowed. onCreateView won't be called for FragmentA and FragmentB after they were added to stack, only in FragmentC onCreateView will be called. For FragmentA and FragmentB only onCreate will be called.
What you can do is -
Use a notification intent in which you pass a string. In your main activity if you receive that string make a fragment stack of A, B and C.
Else if you don't get the intent just continue your flow as it is.
Hardly can't get fragment from backstack, even start thinking of keeping in in singleton which is probably bad.
Saved to backstack like this and all time try to get it by tag or something gives me error.
Fragment fragment = UserProfileFragment.newInstance(null);
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(FRAGMENT_PLACE_RESOURCES, fragment);
trans.addToBackStack("profile");
trans.commit();
It just return me null here so I can't use this fragment. No logs.
Fragment fragment2 = getFragmentManager().findFragmentByTag("profile");
getFragmentManager().findFragmentByTag("tag")
is only used when you have added a fragment with specific tag for e.g.
fragmentTransaction.add(R.id.order_container,mProfileFragment,"profile");
or
fragmentTransaction.replace(R.id.order_container,mProfileFragment,"sometag");
Then you will be able to find this fragment by the tag.
In your case you are adding a transaction to backstack so you will not be able to find that fragment by tag. You just adding a transaction to backstack thats it not a fragment. And also your fragment was removed from the activity and destroyed so you have to revert the transaction by popping backstack instead of finding that fragment by tag.
You have to call
getFragmentManager().popBackStack("profile");
to get that fragment back to the activity and make it visible on screen.
I have a Fragment with MapView in it. I add Fragment to container with following code:
Fragment fragment = new MyLocationFragment()
String tag= fragment.getClass().getName();
FragmentTransaction transaction = fm.beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right);
transaction.replace(R.id.container, fragment, tag);
transaction.addToBackStack(null);
transaction.commit();
Now when user presses back, this Fragment is supposed to be removed from FragmentManager. But if execute this code :
Fragment fragment = getSupportFragmentManager().findFragmentByTag(MyLocationFragment.class.getName());
It never returns null, even if I replace other fragments in same container. What can I do to remove Fragment from FragmentManager? Am I doing something wrong here ?
When an activity is destroyed, its FragmentManagersaves out its list of fragments. When the activity is recreated, the new FragmentManager retrieves the list and recreates the listed fragments to make everything as it was before.
[Refer to book "Android Programming The Big Nerd Ranch Guide" P150]
So your should remove fragment from fragmentmanager.
Refer to this Q&A Remove old Fragment from fragment manager
Your question maybe duplicate with thisHow to get a Fragment to remove itself, i.e. its equivalent of finish()?