Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to do all cleaning up in onDestroy?

More concretely: Is it safe to place the canceling of a task in onDestroy? Also, is it safe to use onDestroy for unregistering receivers and freeing up resources?

My aim is to make sure that my task is canceled/destroyed when the Activity is destroyed, but not before.

onDestroy():

  1. is called when the activity is destroyed and resources must be released.
  2. is NOT called when the activity is destroyed in a hurry (when the system is low on resources etc).

The first case is clear: I do all cleaning in onDestroy and no problems arise. The second case is a bit of a problem though. When the Activity is destroyed and onDestroy is skipped (so I don't cancel my task), could it happen that the task continues execution, then completes and tries to update the dead Activity, so the app crashes?


We come to the real question:

  1. When an Activity is killed and onDestroy is skipped, is everything attached to that Activity automatically destroyed? (Is onDestroy skipped only in case that everything will be wiped out altogether? Tasks, registered receivers etc)
  2. If onDestroy is skipped does this mean that the whole app is being killed?

Let's focus on onDestroy(), because the solution is not in onPause() or onStop(). Arguments:

  • onStop() could be skipped when the Activity is being destroyed, just like onDestroy
  • onPause is called too early and too often, so it is not appropriate for the use case. Examples:

Screen lock: onPause can be called when the device screen is locked. Very often this happens like a screensaver and the user unlocks immediately because he is standing there looking at the screen. Canceling tasks and stopping everything my app is doing in such a case will only degrade user experience. I don't want my app to choke and misbehave just because of an incidental "screensaver".

In an example app I have two screens that are Activities. The user can quickly switch between them. In this app users tend to switch screens often and quickly.

Navigation: One of the screens has a map which receives location updates from the system. It records a precise graphical log of the changes in location (route), so it needs to run constantly until the Activity is closed. Normally I would register and unregister any receivers in onResume and onPause. However, this would make the app very unusable, as the updates on the map will stop every time the user navigates away. Therefore, I would like to unregister the receivers in onDestroy.

Loading list: The second screen has a list that shows data from a webservice. It takes 4 seconds to download the data. I use an AsyncTask and I know I should cancel when necessary. It should not be canceled in onPause, because it should continue loading while the user switches between screens. Therefore, I would like to cancel it in onDestroy.

There can be many more examples. Some of them might not be totally appropriate in everyone's opinion (you might even suggest using a service instead of AsyncTask). But the idea is important, and all of them have the same idea: keep on doing work that's specific to the Activity, while the Activity is paused, but ENSURE to stop doing it when the Activity is destroyed. (It does not matter whether I am using an AsyncTask or a Service. In either case, the work should be stopped when the Activity is destroyed.)

P.S. If the answer is that it is not safe to do the clean up in onDestroy, this would mean that the Android framework requires us to stop everything we are doing in onPause. And then I would not see any reason for using onDestroy...

like image 829
Stan Avatar asked Jan 29 '13 12:01

Stan


People also ask

Why is it necessary to use the onDestroy method?

OS decides when things "go away." The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed but it does not mean that the activity will, in fact, be GCed.

What happens when onDestroy is called?

If onDestroy() is called as the result of a configuration change, the system immediately creates a new activity instance and then calls onCreate() on that new instance in the new configuration. The onDestroy() callback should release all resources that have not yet been released by earlier callbacks such as onStop() .

Is onDestroy guaranteed?

Android Activity onDestroy() is not always called and if called only part of the code is executed. Save this question. Show activity on this post. onDestroy() is not always called.

What is the difference between onStop and onDestroy?

Once onStop() is called then onRestart() can be called. onDestroy() is last in the order after onStop(). onDestory() is called just before an activity is destroyed and after that it is gone it is not possible to resurrect this. Simply destroyed and buried!


2 Answers

I would like to refer you to this baby: http://developer.android.com/reference/android/content/ComponentCallbacks2.html#onTrimMemory(int)

Essentially it gives you all the places where the system finds it useful to cancel tasks and clean its memory:

Please take a closer looks at the following 2 cases:

TRIM_MEMORY_UI_HIDDEN - the process had been showing a user interface, and is no longer doing so.

TRIM_MEMORY_COMPLETE - the process is nearing the end of the background LRU list.

Which are the cases for most of what you asked.

In the same method you can also catch TRIM_MEMORY_RUNNING_CRITICAL which will alert you to a case where the system has no memory and special actions must be taken immediately.

This method has made my development life much better in similar cases.

like image 101
Royi Benyossef Avatar answered Sep 21 '22 14:09

Royi Benyossef


If you just need to do some cleanup, no matter how the activity is closed, you should be able to use a combination of onSaveInstanceState() and onDestroy(). One of those should be called no matter what. Maybe have a boolean cleanupDone in your activity, which is set whenever one of the two finishes.

Concerning saving of user data, have a look at Saving Persistent State:

Google suggest a

"edit in place" user model

That is: save as soon as the user creates new data, at the latest in onPause(). This does not mean that you need to recreate the data in onResume(), just that it should have been saved.

By the way: onStop() can be skipped only on pre-Honeycomb devices, that is, as of June 2015, less than 6 % of all devices. Still, onSaveInstanceState() should be called if either onDestroy() or onStop() are omitted.

like image 32
serv-inc Avatar answered Sep 18 '22 14:09

serv-inc