Many developers after reading the official documentation believe that the system will reap the hidden activities of a task when running out of memory. In this post we will see this is not the case and how to solve the problem.
Let’s take a took at the official docs:
“If an activity is paused or stopped, the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process. When the activity is opened again (after being finished or killed), it must be created all over.”
This simply does not happen. According to this stackoverflow answer by Dianne Hackborn, one of the core engineer on the Android platform, “the only memory management that impacts activity lifecycle is the global memory management across all processes”, basically the out-of-memory killer killing entire processes to reclaim memory. This means in particular that
onDestroy() won’t be called on your activities and that your application will blow up if you keep too many memory-consuming activities in a task.
How to solve the problem? Well, still in the same answer, Dianne Hackborn says to use fragments as they destroy their views when they get to the backstack. To prove this point I coded a simple project (clone from here, then import ActivityLowMemory from the Android folder).
At the start, there is an activity with a single fragment and the fragment loads an expensive bitmap. There are two buttons with two relative counters: how many activities are in the task and how many fragments are in the current activity. If you start launching activities you will see that you run out of memory pretty quickly (at the sixth activity on my Nexus 5X). Instead, if you push fragments, you won’t blow up because
onDestroyView() will be called and the garbage collector will be able to collect the expensive bitmap.
You can check the memory consumption with the Memory View of Android Studio, as seen in the next picture, activities on the left and fragments on the right. Note there is a bit of jag because images are loaded on the UI thread, which is usually bad practice but not the point of this sample.
So can activities ever be “killed”? Actually if the process is killed by the system, or by your main thread blowing up, the information in the activity task is preserved. That is, Android will remember which activities were launched or, more precisely, it will remember all the activities that had saved their state so far. When you resume the task,
onCreate() is called only on the topmost activity, making the other underlying activities effectively “killed”. When you press back and an old activity is to be seen, its
onCreate() is finally called. You can verify this checking the logs in the sample project.
Finally, an official bug has been filed to fix the documentation, but hasn’t been worked on so far. You can star it to raise its priority so that we will all get better documentation.