onDestroyView For Fragment Never Called After onStop
Asked Answered
E

4

7

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();
Expulsion answered 2/4, 2018 at 8:31 Comment(3)
onDestroy after onStop() called only in MainActivityLitchfield
I don't understand the present of fragments in each activity here, why don't you go with one activity and multiple fragments or just only activities?!Monteria
@M.RezaNasirloo I have components created as fragments so that it can be reused in different activities.Expulsion
Z
8

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

Zoometry answered 6/4, 2018 at 7:27 Comment(7)
if i use single task as launch mode, I would lost the activity from the stack, I don't want to do that. I need the user navigation history to be maintained.Expulsion
I think it would be worth to consider whether you need the complete navigation history to be maintained. If a user endlessly switches between A1 --> B1 --> A2 --> B2--> A3 --> B3, is it worth saving all the history? Even if you free the memory in each of the open activity, at some point an OOM will occur (just due to the number of open activities). Usually these switches between screens are due to navigation events between top-level screens. If this is the case, then the complete navigation history is not really required. So if the user does A1 -> B1 -> A1, and presses back, you just exit.Zoometry
I guess you could also just keep your implementation the same (i.e. allow multiple instances of the same activity A1 --> B1 --> A2 --> B2--> A3 --> B3)...but also implement onTrimMemory(int) & onLowMemory() in all of them. When notified with onTrimMemory(TRIM_MEMORY_MODERATE ) you can call finish() on the activities which are not a visible. I have not tested this though, just an idea.Zoometry
Nope this is a E-Commerce app user navigate to multiple products and it wouldn't be better if i remove the history. Am wondering why android does not handle this?Expulsion
It's pretty unlikely you'll get OutOfMemory errors due to having instantiated "too many activities". Activities are kept in different Contexts, and Android destroys activities in the backstack if it needs more memory, then they'll be recreated when navigating back.Geosphere
The docs mention that an activity is never closed by itself, when memory needs to be freed: developer.android.com/guide/components/activities/…. Instead, the whole process is killed. There's another reference here developer.android.com/guide/components/activities/… (search for might begin destroying background to find the note), which does mention that background activities might be killed, but It doesn't specify whether it refers to activities in background or foreground processes. Probably it refers to the former.Zoometry
@CodeDecode, did you solve this? Curious about your approachZoometry
A
1

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"/>
Artistic answered 6/4, 2018 at 7:30 Comment(0)
S
1

the simple solution which i noticed is that

onDestroy()

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

Standstill answered 9/4, 2018 at 20:29 Comment(0)
B
-6

Try this code and add this code into your fragment

@Override
public void onDestroy() {
    super.onDestroy();
}
@Override
public void onPause() {
    super.onPause();
}
@Override
public void onResume() {
    super.onResume();
}
@Override
public void onStop() {
    super.onStop();
}
Bystreet answered 9/4, 2018 at 10:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.