Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Release resources in onPause instead of onDestroy

This is about POST-honeycomb (i.e., Android 3.0+) and the quotes below come from https://developer.android.com/reference/android/app/Activity.html

According to the lifecycle, onStop and onDestroy are killable, this means:

Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may be killed by the system at any time without another line of its code being executed

  1. In other words, onStop (along the others that occur before this event) is guaranteed to be called, yet at the moment the method returns, the process might die, thus onDestroy is not guaranteed to be called.

    Another quote states:

    For those methods that are not marked as being killable, the activity's process will not be killed by the system starting from the time the method is called and continuing after it returns.

    Followed by

    Thus an activity is in the killable state, for example, between after onPause() to the start of onResume().

  2. But this does not correspond to what was said above, unless this only corresponds to PRE-honeycomb. This is not true for POST-honeycomb, right? So basically, both onPause and onStop are guaranteed to be called.

  3. Assuming I only release a resource in onDestroy, then this might lead to a possible leak since onDestroy might not be called, right?

  4. However, can this scenario (i.e., onDestroy is not called) occur besides when the process is killed by android itself? Are there any other scenarios that cause onDestroy not to be called, thus leaking the resource.

  5. Is it true that when Android kills the process that the resources will be destroyed and no leak can occur (even when we did not explicitly released the resource?).

Please provide detailed information whether those statements (1) (2) (3) (4) (5) are correct or not.

like image 914
Captain Obvious Avatar asked Apr 14 '17 13:04

Captain Obvious


Video Answer


1 Answers

First of all let's understand what's going on with the documentation you quoted.

The following commands show git blame output of Activity.java file in AOSP:

$ cd $AOSP/frameworks/base
$ git blame ./core/java/android/app/Activity.java

The relevant part of the output:

9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  363)  * <p>Note the "Killable" column in the above table -- for those methods that
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  364)  * are marked as being killable, after that method returns the process hosting the
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  365)  * activity may killed by the system <em>at any time</em> without another line
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  366)  * of its code being executed.  Because of this, you should use the
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  367)  * {@link #onPause} method to write any persistent data (such as user edits)
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  368)  * to storage.  In addition, the method
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  369)  * {@link #onSaveInstanceState(Bundle)} is called before placing the activity
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  370)  * in such a background state, allowing you to save away any dynamic instance
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  371)  * state in your activity into the given Bundle, to be later received in
550116576 (RoboErik                        2014-07-09 15:05:53 -0700  372)  * {@link #onCreate} if the activity needs to be re-created.
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  373)  * See the <a href="#ProcessLifecycle">Process Lifecycle</a>
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  374)  * section for more information on how the lifecycle of a process is tied
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  375)  * to the activities it is hosting.  Note that it is important to save
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  376)  * persistent data in {@link #onPause} instead of {@link #onSaveInstanceState}
5c40f3fcc (Daisuke Miyakawa                2011-02-15 13:24:36 -0800  377)  * because the latter is not part of the lifecycle callbacks, so will not
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  378)  * be called in every situation as described in its documentation.</p>
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  379)  *
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  380)  * <p class="note">Be aware that these semantics will change slightly between
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  381)  * applications targeting platforms starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB}
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  382)  * vs. those targeting prior platforms.  Starting with Honeycomb, an application
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  383)  * is not in the killable state until its {@link #onStop} has returned.  This
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  384)  * impacts when {@link #onSaveInstanceState(Bundle)} may be called (it may be
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  385)  * safely called after {@link #onPause()} and allows and application to safely
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  386)  * wait until {@link #onStop()} to save persistent state.</p>
0aae2d4e0 (Dianne Hackborn                 2010-12-07 23:51:29 -0800  387)  *
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  388)  * <p>For those methods that are not marked as being killable, the activity's
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  389)  * process will not be killed by the system starting from the time the method
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  390)  * is called and continuing after it returns.  Thus an activity is in the killable
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  391)  * state, for example, between after <code>onPause()</code> to the start of
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800  392)  * <code>onResume()</code>.</p>

Note that the paragraph that discusses post-Honeycomb behavior was added by Dianne Hackborn on 2010-12-07, whereas the enclosing paragraphs date back to 2009-03-03.

What it tells us is that Dianne added the new paragraph without updating the rest of the javadoc, therefore the contradiction. Unfortunately, this is not rare in Android.

To your questions:

1) On post-Honeycomb versions of Android both onResume() and onStop() are guaranteed to be called (as stated by Dianne Hackborn in her addition to Activity's javadoc).

2) On pre-Honeycomb only onPause() is guaranteed to be called (as stated by the earlier version of Activity's javadoc)

3,4,5) onDestroy() will not be called only if the process hosting the entire application is killed. When the process is killed, all resources allocated to it are freed, therefore there is no risk of memory leak in this case.

Important note: since releasing resources in onDestroy() will not cause memory leak, it might look like a good idea to put all the "releasing" code there. However, it is rarely the optimal approach. Why? Read below.

When Activity goes to background it is stopped, but not destroyed (usually). Activity can remain in this "stopped" state for quite a long time, and will be started again if the user returns to the application. If you release resources in onDestroy(), which is not called by default when Activity goes to background, the Activity will hold to these resources while in stopped state, thus causing higher amount of resources to be consumed by your app in background state.

When Android runs out of memory, it starts killing the processes in order to free the memory consumed by them. One of the most important considerations taken into account when choosing which processes to kill is their resource consumption. Thus, if your app holds to resources while in background stopped state, it will have higher chance of being killed by Android.

In addition, we, the developers, must make sure that we make the best apps for our users. Application that consumes non-minimal amount of user phone's resources and battery while in background is not a good application. And the users will know about it!

Therefore, I strongly advice releasing all resources in onStop() method. I don't usually overwrite onDestroy() methods in Activities and Fragments at all.

Corollary: As pointed out by @Juan in his comment, the above important note has an equally important, but not so evident corollary: onStart() should be the only method in which resources are being allocated. Whatever your definition of "resources" is, neither onCreate() nor onResume() should allocate these resources.

like image 92
Vasiliy Avatar answered Oct 18 '22 17:10

Vasiliy