Why my fragment is not destroyed - android

I try to replace Fragment A by a Fragment B but the onDestroy() method is not called on the Fragment B.
Broadcast receivers are unregistered and threads are killed before replacing the fragment.
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transac = manager.beginTransaction();
transac.replace(R.id.content_fragment_A, fragmentB, myTAG);
transac.commit();
Why is my Fragment A not destroyed ?

A Fragment's onDestroy() is called when the Activity's onDestroy() is called. In your scenario you are just replacing Fragments but you didn't destroy your Activity yet. If you want to check on this try to destroy your Activity after you replace your Fragment, both fragmentA and fragmentB onDestroy() should be called.

I would look more into the fragment activity lifcycle
http://developer.android.com/guide/components/fragments.html#Lifecycle
When are adding the new fragment to an existing ViewGroup, for replace function:
Replace an existing fragment that was added to a container. This is
essentially the same as calling remove(Fragment) for all currently
added fragments that were added with the same containerViewId and then
add(int, Fragment, String) with the same arguments given here.
and a remove
Remove an existing fragment. If it was added to a container, its view
is also removed from that container.
From this terminology, I assume that onDestroyView() is being called and not necessary onDestory right away.

Related

How to handle fragment backstack

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);

android fragment transaction lifecycle not called when remove

someone can help me to understand why the lifecycle method Stop and Destroy are not called with fragment manager transaction when you use a single transaction add/ remove ?
I have a single container ( RelativeLayout ) in which I can add or remove many fragments. Case with only two fragments. Fragment_A is already added in previous transaction.
now if I do this below, everything works fine: The lifecycle methode OnPause and OnDestroy of fragment_A are called.
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(myId, fragmentB);
trasaction.commit();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.remove(fragmentA);
trasaction.commit();
if I do this below, the lifecycle method OnPause, OnDestroy are never fired for fragment A ( I checked the fragment inside the manager and the fragments are well added / removed ):
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(myContainerId, fragmentB);
transaction.remove(fragmentA);
trasaction.commit();
I tried to use transaction.setResorderAllowed(false) but whatever, my lifecycle doesn't go until destroy with single transaction. ( I can not use replace, I really need add/remove )
Thanks for your help.

Does replacing a fragment destroy all hidden fragments

If I have an Activity and I add fragment1, hide fragment1, add fragment2, hide fragment2, then use
fragmentManager.beginTransaction()
.replace(R.id.content, fragment3)
.commit();
to now replace in fragment3, what happens to fragment1 and fragment2? Do they get destroyed or something or are they still there? (this is all within the same container, R.id.content)
Unless you add the transaction to backstack, all the the fragments in the container are getting destroyed
If the fragment was added to the back stack, the fragments object instances will have onDestroyView() called, and the data required to reconstruct the fragment is still part of the fragment back stack, so that when fragments are popped off the stack, the prior fragments can be reconstituted and displayed again (similar to activities that may have been destroyed in the activity stack). If the fragment was not part of the back stack, it is simply destroyed because the user can never come back to it.

Fragments not destroyed when recreate() activity

I have a support library fragment that sends a network call, and recreate() the parent activity when it receives a specific network response. I can see that the activity does get recreated as I can see the onCreate() and onDestroy() are called.
But after the activity is recreated, the fragment is still there and it got stuck in a loop which keep recreating and making new fragments.
Here's part of the onCreate() of the activity:
if (someLogic()) {
fragmentA = new FragmentA();
FragmentUtil.addFragment(getSupportFragmentManager(), fragmentA);
} else {
fragmentB = new FragmentB();
FragmentUtil.addFragment(getSupportFragmentManager(), fragmentB);
}
FragmentA is the one that does the network call, and FragmentB is the fragment that should be displayed after the recreate(). When I check the list of fragments with getSupportFragmentManager().getFragments() I see 1 instances of FragmentA, and 16 instances of FragmentB.
My question is why does this happen, and how do I fix it?
Calling recreate() essentially causes the Activity to go through a configuration change. A configuration change causes both the Activity and its Fragments to be destroyed and recreated. So your Fragments should in fact be destroyed when this occurs (you can see for yourself by adding a Log message in your fragment's onDestroy method).
The fact that configuration changes cause fragments to be destroyed and created however does not mean that the FragmentManager will simply forget the fragments ever existed. The FragmentManager will still hold a reference to the newly created fragment after the configuration change occurs.
One thing you can do to prevent multiple fragments from being created is by doing something like this in your activity's onCreate():
if (savedInstanceState == null) {
// The Activity is being created for the first time, so create and
// add new fragments.
} else {
// Otherwise, the activity is coming back after being destroyed.
// The FragmentManager will restore the old Fragments so we don't
// need to create any new ones here.
}
I had same situation as #spy wrote, recreating the Activity after Day/Night mode is changed. Activity had four Fragments which they get restored after Activity.recreate() is called, because FragmentManager saves them as #Alex Lockwood stated. But restoring and not adding Fragments after recreation does not help me because of some architectural reasons of project, i wanted them to disappear.
Solution is to delete Fragments from FragmentManager just before Activity.recreate()is called, in my case it is in Activity.onStart():
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment fragmentA = fragmentManager.findFragmentByTag("fragmentATag");
if(fragmentA != null)
fragmentTransaction.remove(fragment);
// Find and delete other Fragments
fragmentTransaction.commit(); // or commitAllowingStateLoss()
recreate();
This way you will not get Fragments restored when Activity.onCreate() is called.

Fragment methods: attach(), detach(), remove(), replace(), popBackStack()

I am very confused between these functions and their purposes. What I have observed that using replace() replaces the existing fragment with a new one. We can use addToBackStack(null) to put that fragment in back stack so we can go back to the previously shown fragment. Now when a fragment is added (or replaced) - onAttach() -> onCreate() etc.... methods of the fragment are called in order.
Now when we call remove() on the fragment from our activity, which functions of the fragment are called and in which order?
What does attach() and detach() do? Does detach() remove the fragment? And when these two attach() and detach() are used, which functions of the fragment are called and in which order??
Also, what happens on popBackStack()?? I mean which functions are called when we use popBackStack()on the fragment from our activity??
And when does onDestroy() called??
Thank you.
Now when we call remove() on the fragment from our activity, which functions of the fragment are called and in which order?
Look at http://developer.android.com/reference/android/app/Fragment.html .
The order is: onPause(), onStop(), onDestroyView(), onDestroy(), onDetach()
What does attach() and detach() do? Does detach() remove the fragment? And when these two attach() and detach() are used, which functions of the fragment are called and in which order??
attach() and detach() is respectively associates or detaches the Fragment with/from the Activity. When attaching the Fragment, the onAttach() lifecycle method is called, when detaching, the onDetach() lifecycle method is called in the Fragment. For more information look at the link above.
Also, what happens on popBackStack()?? I mean which functions are called when we use popBackStack()on the fragment from our activity??
If the Fragment hasn't been destroyed, then on popBackStack() the onStart() and onResume() methods are called. If the Fragment has been destroyed previously, then the lifecycle methods will be called starting from onAttach(). It's the same as, when you press the back button on Activities.
Just a note on popBackStack(). It doesn't pop a fragment, it pops a fragment transaction. So whatever the last fragment transaction was is reversed. If you were displaying a FragmentA and your transaction was:
fragmentTransaction.replace(R.id.your_layout, fragmentB);
fragmentTransaction.addToBackStack(null);
It would replace FragmentA with FragmentB, and add that transaction (not the fragment) to the back stack. If you then hit the back button, it pops the back stack and gets the transaction, which was "replace this FragmentA with a FragmentB". It then reverses that transaction. Backwards, the instruction is to replace whatever the current fragment is with FragmentA. If the original FragmentA still exists, it uses that one. If it's been destroyed, it makes a new one.
Suppose fragment A and fragment B was added to a container with the following steps:
1. Added fragment A => .replace(R.id.container, fragmentA) => addToBackStack(null)
2. Added fragment B => .replace(R.id.container, fragmentB) => addToBackStack(null)
3. Removed fragment B => fragmentManager.popBackStack();
Callbacks when fm.popBackStack() is called:
FragmentB: onPause()
FragmentB: onStop()
FragmentB: onDestroy()
FragmentB: onDetach()
FragmentA: onCreateView()
FragmentA: onViewCreated()
FragmentA: onActivityCreated()
FragmentA: onStart()
FragmentA: onResume()
Explanation: Why while removing and destroying fragment B using popBackStack(), fragment A view was created again and resumed?
Ans: When you added fragment B, you used replace() and addToBackStack(), so all the fragments were removed from the container, and fragment B was added to the container. And, also this transaction was recorded in the Back stack. So, when fm.popBackStack() is called, first the transaction is popped out from the back stack and so the operations reverted itself, therefore fragment b is removed from the container and destroyed. And all other fragments get added, for our case fragment A's view is added to the container. Also noted that fragment A's onAttach & onCreate() is not called because it has already been created & attached to the MainActivity earlier.
Back press on fragment B does the same thing:
If you press the back button, it calls fm.popBackStack() and pops the transaction.

Categories

Resources