Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

onDestroyView For Fragment Never Called After onStop

My APP does have multiple fragments and activities, Most of these activities hold different fragment, This is to make my components reusable easily. I am facing an issues when I'm loading other activities to the activity stack.

Case
Launched ActivityA-->ActivityB-->ActivityC

All these activities hold different fragments but the problem is when ActivityB is launched from ActivityA the fragments which is in ActivityA onDestroyView is not called though onStop is getting called.

My APP allows infinite number of navigation from one to another when I go on adding too many activity to the stack app throws OOM exception gradually.

Find below the code which I use to add the fragment to the fragment back stack.

final android.support.v4.app.FragmentTransaction ft =
                fragmentManager.beginTransaction();
if(transaction.mInAnimation != FragmentTransaction.FRAGMENT_NO_ANIMATION &&
                transaction.mOutAnimation != FragmentTransaction.FRAGMENT_NO_ANIMATION) { 
    ft.setCustomAnimations(transaction.mInAnimation, transaction.mOutAnimation);
}
String tag;
if(transaction.isRoot){
   clearFragmentStack();
   tag = "0";
}else {
   tag = fragmentManager.getBackStackEntryCount() + "";
}
final AtomicFragment fragment = transaction.compile();
ft.replace(transaction.mFrameId, fragment,  tag);
ft.addToBackStack(tag);
ft.commit();
like image 600
CodeDecode Avatar asked Apr 02 '18 08:04

CodeDecode


3 Answers

So your problem seems to be that "when you go on adding too many activity to the stack app throws OOM exception gradually", and you think that the cause could be that onDestroyView() is not called on the top Fragment, when switching activities.

OnDestroyView()

First, when you go from Activity1 to Activity2, most likely onDestroyView() is not called on your Fragment in Activity1 because you didn't call finish() in Activity1, after starting Activity2.

This means that your Activity1 is alive and well in the activity backstack, but stopped (i.e. onStop called). Since Activity1 is alive, so is its backstack & fragments. The fragment at the top of the backstack of Activity1 will also be just stopped. So basically, Activity1 is in a state similar to the one it enters when you send your app to the background using the Home button.

Among other cases, onDestroyView() is called on a Fragment when another fragment is added above it in the fragment backstack. However, it has no knowledge about the activity backstack/activity tasks whatsoever.

If you want to clear the view of your fragment, you can do it manually (i.e. fragmentManager.popbackstack(), or beginTrasaction.remove(...)), or you can close Activity1 after starting Activity2(i.e. call finish()) - this will also free your memory and call onDestroyView() on the top fragment in Activity1.

OutOfMemoryException

...when I go on adding too many activity to the stack app throws OOM exception gradually.

Most likely the source of your OOM crash is that you have too many Activity instances in your memory and not that onDestroyView() is not called on certain fragments. I also assume you have multiple instances of the same Activity.

Please consider using android:launchMode="singleTask"(reference) when declaring your Activities in AndroidManifest.xml. This ensures that you'll only have a single instance of a certain Activity within your given task. This, by itself should fix your OutOfMemory issue if it was caused strictly by too many instances of the same Activity.

This approach by itself will imply certain additional handling from your part, to reset a reused activity's UI/state back to a "clean" one. Luckily, you can rely on onNewIntent(...)(reference) to detect when you need to do that.

Later edit: Memory Monitor

Regarding searching for the cause of your OutOfMemory error: Please use the Android Memory Monitor to search for memory leaks. I found memory leaks to be pesky little devils and using the Memory Monitor from the start is always better when compared to (informed) guessing.

In your case, after using your app for a while, and after performing a few activity switches, you need to see whether you have several instances of a particular activity (Activity1 for instance), in memory.

Basically, you need to look for something similar this: enter image description here

Just remember to force the garbage collector a few times(just once is not enough) before taking the heap dump. This is to make sure that references which would be garbage collected at some point won't appear in your dump.

Hope this helps

like image 143
cjurjiu Avatar answered Oct 05 '22 08:10

cjurjiu


the simple solution which i noticed is that

onDestroy()

will be called instead of onDestroyView() so that you can use onDestroy()

like image 28
Pranav Ashok Avatar answered Oct 05 '22 08:10

Pranav Ashok


As you are allowing infinite number of navigation from one to another activity, A new instance of the activity is getting created every time you start an activity. To stop it from getting created multiple times, make the activity to be created only once so that only one instance of that activity will be created. To do that add this line in your manifest file in tag like this:

<activity android:name=".MainActivity"
        android:launchMode="singleTop"/>
like image 23
Birju Vachhani Avatar answered Oct 05 '22 10:10

Birju Vachhani