I'm trying to execute some code whenever my activity is killed, but not when it's simply moved to the background (so just calling it in onPause() isn't a solution), and I understand onDestory() is not guaranteed to be called. I've been searching all over and haven't found a way to do this. How can I go about tackling this problem? Is it possible?
Nothing. You can never be guarantied to be called when an app ends, because it can always be terminated abnormally- it could crash, the battery could be pulled out, etc. onDestroy is the closest you can come. But you should never write a program that requires cleanup at termination time.
I'm not sure, but I suspect you've got a few issues which you've conflated into one large issue;
As I read this question you have 2 or 3 concerns:
1) You want to garuntee something happens when the app exits.
2) You have state you want to maintain during onPause() but not after onDestroy()
3) You presumably have some content which should not persist between application usages.
Some answers:
1) As Gabe points out - there is no guarantee anything will ever be called. I can pop the back off the device and pull out the battery. Your calls aren't going to happen.
2) You might try onDestroyView() for this case. It won't be called in many circumstances in which onPause will be (for example when an alert dialog is shown), but will be called in others (when you replace a fragment with another fragment for example).
3) This issue makes me think you may want to reconsider your method of storing/saving this information. If you don't want it to exist on the system when you app isn't in use, it is best to never write the data to the filesystem. (Due to 1). Other options are keeping it in memory. You could also use shared preferences/preferences mechanism but this will still exist on the filesystem until your app is removed.
Related
I know this question has been asked a million times, I myself though that I already knew the answer and that the correct one was that the only guaranteed call is to onPause(), so you should save your data there.
However, in many places of android documentation they always suggest not doing heavy work (such as writing data in database) in the onPause() method as it will delay the transition between the activities.
According to Android Developer Guide in Table 1
onPause(): This method is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, and so on. It should do whatever it does very quickly, because the next activity will not be resumed until it returns.
Killable: YES
Then according to Android Developer Reference Guide in the similar table.
It says the same thing but:
Killable: Pre-HONEYCOMB
And they add a little note that says:
Be aware that these semantics will change slightly between applications targeting platforms starting with HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts when onSaveInstanceState(Bundle) may be called (it may be safely called after onPause() and allows and application to safely wait until onStop() to save persistent state.
Killable
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 killed by the system at any time without another line of its code being executed.
FOR POST-HONEYCOMB (i dont care about earlier versions):
So, is it OK to assume that any Android device (including different ROMS) will ensure a call to onStop on the activity? And this is the best place to make any time consuming storage writing of the App?
Note: This is extremely confusing as most answers here, sites, books, and even online android tests take as a correct answer that you should save it in onPause and NOT in onStop.
When to save data to database, onPause() or onStop()?
Either. They are nearly identical, particularly on Android 3.0+.
If the activity that is taking over the foreground is a typical full-screen activity, so that the earlier activity is no longer visible, onPause() and onStop() will be called in rapid succession.
If the activity that is taking over the foreground is themed to be more like a dialog, where the earlier activity is still visible, onPause() will be called, but not onStop(), until such time as the activity is no longer visible (e.g., user now presses HOME).
Most apps aren't worried about the "themed to be more like a dialog" scenario, in which case onPause() and onStop() are called one right after the next, and you can fork your background thread to save your data in whichever of those makes sense to you.
However, in many places of android documentation they always suggest not doing heavy work (such as writing data in database) in the onPause() method as it will delay the transition between the activities.
The same is true of onStop(), as both of those methods are called on the main application thread.
So, is it OK to assume that any Android device (including different ROMS) will ensure a call to onStop on the activity?
Both onPause() and onStop() will have the same characteristics from the standpoint of process termination. Either both should be called (normal case) or neither will be called (e.g., you crash, the battery pops out the back of the phone).
And this is the best place to make any time consuming storage writing of the App?
Either onPause() or onStop() are fine places to trigger the work, done on a background thread, to persist your data. If you prefer to do that work in onStop(), you are absolutely welcome to do so. Personally, I'm an onPause() kind of guy.
If you want more safety, storage in onPause.
If your data is so big that you have to storage it for several seconds, you may open a background Service (e.g. IntentService) to save.
You can also check the system version in your code and choose when to save. if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.ICE_CREAM_SANDWICH){}
In most situations this rule of when to save will not be changed by some customed os. But of course there can be some other os which certainly changed it. So the most important thing in android development is that u need to know that everything can be different in different phones.
I know this question is prehistoric, but it seems like people like me still happen to land on this question. So I guess it may make sense to add an answer I found in the documentation, which states:
To save persistent data, such as user preferences or data for a database, you should take appropriate opportunities when your activity is in the foreground. If no such opportunity arises, you should save such data during the onStop() method.
source
But wait, there's more:
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. Because of this, you should use the onPause() method to write any persistent data (such as user edits) to storage.
source
So wrapping up, it seems like persisting data onPause() is the best thing to do.
The documentation suggests that the data should be committed/read in onPause()/onResume().
Yet when the application is no longer in the foreground, its data structures remain intact, which suggests that one could delay committing/reading data until the application is no longer visible, i.e. in onStop()/onStart(). Particularly since onStop() is guaranteed to be called before onDestroy().
Is it perhaps the case that either approach is suitable? Is the documentation giving here merely a guideline?
Update
Suppose your application needed to save relatively substantial data, say edits to a large image. One would then surely not write/read in onPause()/onResume(), lest the user experience become sluggish. One would in that case choose instead to write/read in onStop()/onStart(). Is that true?
The problem with using onStop is that you have no guarantees on when it will be called since the only sure thing is that it will be called before onDestroy. If you wait until onStop to commit your data it may be to late for another activity to show/use any of those changes. Same thing applies to onStart, your activity may not need to be restarted if it was just in the background so you'll have stale data. Using onResume and onPause guarantees that your data will always be current, commits are made as soon as the activity goes to the background and new data is loaded as soon as it becomes visible.
Yes, it is just a guideline (and generally a good one). It is up to you exactly when you want to commit changes. I personally like to create Store Objects that allow a simplification of Databases or SharedPreferences, and when a change is made, I commit those changes immediately. For simple data storage, this will be quick and invisible to the user. For large data sets, this may take more time, and you may wish to make those writes on a time interval, as well as in onPause.
As for when to read - you can read whenever, but again longer reads will often affect the user experience, unless you have taken care of it in another thread, such as with an AsyncTask.
To Further answer your update:
It depends on the developer, however I would write in onPause() and if necessary, read in a separate thread, probably initialized with onResume(). I may also write data out on a scheduled interval using a Timer thread, depending on how it would affect the user experience for the current session, and if it would be catastrophic for the phone to turn off and lose all data before onPause() is called.
The true answer to this is, onPause is the only method you are guaranteed to get called before Android can destroy your process. If a user leaves your app to take a phone call, and Android decides to close your process, its entirely legal for you to only get an onPause call. If you hadn't saved your state there, when the user hits the back button, you will end up recreating your activity in a different state than the user left it in.
I want to know when the app is closed, because I need to erase a Database when the user shutdown the app, just in the moment when the user close the app is the right moment to erase the SQLite Database, how can I detect this?
This is a flawed design idea, which reflects a misunderstanding of the system - when the process overall dies, it's dead, meaning your code is no longer running.
You can do some tracking and have the last onDestory()'d activity do the cleanup as a courtesy, but don't assume that it will always actually happen (the method is not always called). If having a stale copy is a problem, clean it up on the next run.
That said, you can try using the ndk to provide a handler for process termination signals, but still I wouldn't count on it working in all cases. The limited potential to gain any sound functionality from this would probably not justify the effort unless you are already familiar with the concepts involved.
And do not for a minute mistake cleaning up for a security mechanism, as the file is there while your app is running, and would remain if your app terminated in an unexpected way.
Supposing you don't finish() your main activity, clearing your database inside the onDestroy() method of that activity might be the closest of what you want to accomplish. As has been pointed in the comments, refer to http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle.
As you all knows all android activities create, start, resume, run, pause, stop, destroy. This process is shown well in the android manual.
In this lifecycle is there any possiblity to understand activity is created which way? I mean how can I understand whether activity is called directly or activity is created once then killed by android os and then recreated since user navigates back?
More basically how can I understand whether an activity is in its second life or first life?
Edit: Why do I need this?
In my design I have a main page where the data is loaded from the net. And when the user clicks some details, it puts the data in a static object just like session in web. This works well normally.
But when a user starts detail activity in second life, he data in static object is killed, and I got nullpointer exception.
I have 4 projects having same architecture so I want to solve this problem.
You've already got the flow chart information there. You can always keep some state for later use by storing the fact of your Activity's demise during onDestory() or similar. Then, the next time your Activity is resumed, you will know if you were actually destroyed or just stopped. I don't think you get any of that information for free from the OS, since it's not supposed to matter in the ideal case.
you should not distinguish between these, since even after it has been destroyed (at least the method has been called) it might "come back" just in the state as it was when it was destroyed. Which could be different than from the very initial state when it was created the first time.
Please explain the reason why you need this - you should "rethink" your issue, since Android is really behaving "strange" concering this question.
It is better to design your project livecycle according to Android system behaviour - which is actually not documented anywhere regarding this point (at least I have not come accross any good doc so far)
If I understand your question, you want to know when your activity has been destroyed by the OS or when it has only been paused. Simply use logcat statements:
onPause() {
super.onPause();
Log.v("Activity", "Paused");
}
onDestory() {
super.onDestroy();
Log.v("Activity", "Destroyed");
}
You can do the same for onCreate(), onResume(), anything really.
Right so here I am obsessing over memory leaks, and quite frankly not understanding what could really lead to one (and yes I've read the usual links such as http://kohlerm.blogspot.co.uk/2009/02/memory-leaks-are-easy-to-find.html).
I've tried to create some on purpose, for example by leaving a PhoneStateListener subclass inside my activity and opened and closed it a bazillion time, can't see anything in DDMS heap or MAT out of the ordinary. Yet on SO I read over and over again that not only it needs to be deregistered onDestroy, but also onPause (PhoneStateListener() isnĀ“t finished)
Question: is there such a list?
Bonus question: is it true that a PhoneStateListener will create leaks unless it's deregistered onPause/onDestroy etc.
UPDATE: I stand corrected. When re-spawning my app over and over again, even in singleinstance mode, the PhoneStateListener(s) it has registered are still alive after onDestroy was called, and start adding up. I'm currently working on an elegant way to kill them, and will post my results here.
UPDATE2: The correct way to deregister the listener is:
instanceOfTelephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
... according to the API
UPDATE3: As promised linking this to a better phrased question: https://stackoverflow.com/a/4607435/821423
It is good practice for activity to clean up after yourself and prepare to die in onPause() - this is always called before it goes out of focus, and can not interact with user. onDestroy() is possibly called after this (but not guaranted).
Is your activity is not in focus for user, it does not need any listeners anymore, as it can not show results of those listeners.