Android contradicting documentation about lifecycle callbacks onPause() and onStop() - android

Intuitively, the most applicable callback to perform stuff in it would be onPause(). Yet, there seems to be a contradiction in the documentation:
According to https://developer.android.com/guide/components/activities/activity-lifecycle.html:
onPause() execution is very brief, and does not necessarily afford
enough time to perform save operations. For this reason, you should
not use onPause() to save application or user data, make network
calls, or execute database transactions; such work may not complete
before the method completes. Instead, you should perform heavy-load
shutdown operations during onStop().
You should also use onStop() to perform relatively CPU-intensive
shutdown operations. For example, if you can't find a more opportune
time to save information to a database, you might do so during
onStop().
According to https://developer.android.com/reference/android/app/Activity.html:
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.
So, where should it be done and on another spawned thread? How is this commonly done?

Good catch!
Some notes to sum up:
don't use onPause() for "really heavy-load shutdown operations", otherwise you risk to get a negative user experience by slowing down a "next activity to be resumed until this method returns." In other cases go with it;
if you still hesitate, use onSaveInstanceState(). It's called between onPause() and onStop() and, AFAIK, is guaranteed to be called. The system relies on the method "so that when an activity has been killed, the system can restore its state coming back to it in the future";
regarding onStop(), personally I have never! experienced killing my app's process until the method returns, but seen SO questions stating so, which, as we know, corresponds to the official documentation. But, it's really very rare. So it's up to you whether to rely on it or not.

Related

Finally, where is it better to persist data on android, onPause() or onStop()?

I've seen in some places that it is okay (or even advisable) to persist data in the onPause() method.
Like here
https://stackoverflow.com/a/41778266/3913107
and here
https://stackoverflow.com/a/29496430/3913107
However, the documentation states:
onPause() execution is very brief, and does not necessarily afford
enough time to perform save operations. For this reason, you should
not use onPause() to save application or user data, make network
calls, or execute database transactions; such work may not complete
before the method completes. Instead, you should perform heavy-load
shutdown operations during onStop()
https://developer.android.com/guide/components/activities/activity-lifecycle#onpause
What am I missing?
So that documentation is a little dated. For example it says not to do networking in onPause- you can't anyway. Networking needs to be on a thread other than the main thread, and onPause is always called on the main thread. You could send off a request to another thread to do networking, but that isn't a problem no matter where you do it.
The tradeoffs between doing it in onPause and onStart is when its called. onPause is called when the Activity is no longer foreground. onStop is called when the activity is totally off screen. So onPause will be called in a few situations without calling onStop. This makes me prefer onPause.
The real lesson is that both onPause and onStop should be fast. Don't do a lot of work in either. If you need to do something that isn't quick, do it on another thread. Of course that goes for pretty much everything on the main thread- if it isn't quick, do it somewhere else.

Confused by asynchronous mechanism

I am confused by the fact that android is multi-threaded. If the code of a particular activity method is executing, can it be interrupted in the middle by onPause(), onStop() or onDestroy() or by another method like the onPostExecute() of an asynctask?
Edit 1
This question is not about activities life-cycle. What i am really asking is if the onPause() method can interrupt the onClick() method (just an example) and i would like to read more about how exactly android manages activities, calls their async methods etc...
Edit 2
Ok, it seems that i have found the relevant information i needed in the developer docs (don't know if it is explained better somewhere else): Threading Performance:
Internals
The main thread has a very simple design: Its only job is to take and
execute blocks of work from a thread-safe work queue until its app is
terminated. The framework generates some of these blocks of work from
a variety of places. These places include callbacks associated with
lifecycle information, user events such as input, or events coming
from other apps and processes. In addition, app can explicitly enqueue
blocks on their own, without using the framework.
It states that callbacks relative to activity lifecycle, user events such as input and other code are all managed using a "thread-safe work queue". This is central to understanding Android asynchronous programming. It explains a lots of things, such as why onClick() will be never be interrupted by activity onPause(), or why onClick() will be never be interrupted by a runnable posted using a Handler object (allocated in the main thread). So, for example, the onPostExecute() of an AsyncTask cannot interrupt the onClick() method (or onStart(), onResume(), onPause() etc...). As a novice android programmer, it was a bit confusing at first.
According to your question, I think you need to understand basic about Android Application's life cycle.
Basically, the life cycle deals with the state of application in different different situation.
Like what will be state when application goes, in foreground or background and all that So These cycles state that you had mentioned like onPause(),onDestroy(), onStart(), onCreate().
Now talk for AsynchTask(), If you want to execute long running process like downloading image or listening musing or any other then we will use BackGround services. So don't get confusion between life cycle method and background services. .
Third, App will close only some rare condition like if memory is not sufficient or some other fatal issue occur in App then only it will terminate.
So, findings are that Thread is meant for long running process and Activity Life Cycles method are meant for various activity state
Please follow this tutorial and I hope you will get clarification
This is a good question to ask I think. However, Here is my understanding:
When an Application starts, a Dalvik Virtual Machine (DVM) is assigned to it and works separately. So no two Applications interrupt each other as each of the application is managed by separate DVM.
Coming to Activity, it is a component of Android and runs on main thread. Android OS manages priority level to it's components. It gives high priority level to Activity, Services and may be other component(s). The OS maintains the non interruption behaviour of main thread.
Further when you run an AsyncTask, it is a long running task in background but dependent on Application context. So the OS does not guarantee to manage it.
Now regarding activity life cycle. As #nihal_softy said, activity has it's own life cycle which start from onCreate() and encounters onStart(), onResume(), onPause(), onStop() and onDestroy(). You can call these methods from anywhere of your Activity or from an AsyncTask and it will called but does not mean that the Activity will go in background or will destroy. In a simpler word, if you call onPause() from an AsyncTask, it does not mean that the Activity will be sent to background (if in foreground). Because when an Activity will go in background then it calls it's life cycle methods such as onPause() and onStop() as callback. But converse is not true.
I hope my understanding will help you to get the answer.

Can we rely on onStop() being called?

Concerning Android's Activity lifecycle, I've seen it widely claimed (on SO and elsewhere) that persistent data should be saved in the onPause() method, because there is no guarantee that onStop() will be called, since the OS may need to kill the activity to reclaim its resources if system resources are running low.
However, in a book I'm reading, the opposite is stated:
Practically speaking, the OS will not reclaim a visible (paused or
resumed) > activity. Activities are not marked as "killable" until
onStop() is called and finishes executing.
[Talks about stashed
state and activity record a bit]
Note that your activity can pass into the stashed state without
onDestroy() being called. You can rely on onStop() and
onSaveInstanceState(Bundle) being called (unless something has gone
horribly wrong on the device) ... Override onStop() to save any
permanent data, such as things the user is editing, because your
activity may be killed at any time after this method returns.
p70-71, Android Programming: The Big Nerd Ranch Guide, 3rd Edition
(emphasis mine)
Multi-Part Question:
Is this (possibility of an app being killed before onStop() is
called) something that is no longer true in and is still being
propagated, or is the book outright wrong?
Is there some nuance to when or why an Activity might be killed that
makes the answer "sometimes?"
If the book is correct, why is that misconception so widely spread? (E.g. Here, here, and here.)
References to official documentation would be appreciated.
This is an illustration of Activity lifecycle :
According to the official Android documentation,
onPause() execution is very brief, and does not necessarily afford
enough time to perform save operations. For this reason, you should
not use onPause() to save application or user data, make network
calls, or execute database transactions; such work may not complete
before the method completes. Instead, you should perform heavy-load
shutdown operations during onStop(). For more information about
suitable operations to perform during onStop(), see onStop().
There is a case when the app go from onPause() to onCreate() without onStop() and onDestroy() is when another app with higher priority needs memory as you see the illustration.
Also, The activity could be destroyed without calling onStart(),
onStop() when you call finish() method on onCreate() see reference

How can we guarantee that onPause will be called?

Going of this question
android save game state in onPause or onDestroy?
The answer highlighted that the person asking the question should save game state in onPause because the onDestroy documentation says "There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away." In these situations, how can we ensure onPause will be called? Is it possible to control what methods are called in these situations? Seems unpredictable
onPause will be called every time your activity leaves the screen, before it is finished or if something overlays your activity that keeps the user from interacting with your activity.
You don't need to worry that onPause is not called.
For more information look into the starting and stopping activity training or the Lifecycle Api Docs
You should save temporary instance state in onSaveInstanceState(). This method recieves a Bundle parameter which you can use to write state to. The Bundle is then sent to onCreate() when your app is restarted.
If you need to save instance state more permanently, then save it to a database or SharedPreferences. According to http://developer.android.com/training/basics/activity-lifecycle/stopping.html, you should use onStop() for more CPU-intensive operations rather than onPause(). I don't think you need to worry about onPause() being called in normal use cases. As far as I can tell, it is guaranteed. (Of course, there are always catastrophic failures, such as the user pulling out the battery of the device, but there's not much you can do about that.)
It's almost certain that onPause() will always be called. The reasoning is that it's highly unlikely the "system" will aggressively kill an active (i.e., visible) Activity.
In order to free resources, the Android OS effectively reserves the right to kill dormant processes - in particular ones that have been long-running but not recently used. In order for your Activity (and its process) to qualify for this, at some point you must have sent the Activity to a background state, e.g., pressed HOME or started another app's Activity. The simple fact your Activity is no longer visible means it will have been paused and onPause() will have been called. It's almost certain that the Activity will have been stopped and onStop() will have also been called.
What you have to remember is Android has been around for a while now and early devices had RAM measured in 100s of MB and the system behaviour possibilities and documentation reflects this. More recent devices have RAM measured in GB (even 10s of GB) so unless a user really pushes their device to the limitations of its resources, aggressive clean-up of app processes becomes less likely.
You can show Dialog for User to Act Accordingly.When Dialog will be opened to ask user that he wants to quit or not,Activity will definitely call onPause() and at this time you can write your game state saving code. Its better to write code on onPause() because at onDestroy() resources are freed by os.

Android background thread management and activity lifecycle

I have an activity in which I collect data for an online transaction. When the collection is done, I run a background thread (more specifically an AsyncTask) that calls a web-service and waits for its response, then return it to the activity. Meanwhile, a progress dialog shows up.
I want the background process to be cancelled if the application finishes or user cancels (however, I still need to notify the web-service), and retained if the activity is destroyed due to a configuration change or to free memory. I understand that I shall use onRetainNonConfigurationInstance() to detach my activity from the AsyncTask, retain it, and then reattach in the next activity, I already have the infrastructure for that. I also know that in some lifecycle callback, the isFinishing method tells me if my app is shutting down normally; and I do believe I can also handle the user cancel in the progress dialog's callback.
I have two simple questions:
Will onRetainNonConfigurationInstance() be called if my activity is
killed due to low memory? (I know it will be if the reason is a
configuration change.)
What is the situation (as emphasized by the developer guide) in which onStop() and onDestroy() are not called? (I want to know if my
code handling the cancellation would always execute.)
All in all, can I be sure that by implementing onRetainNonConfigurationInstance() and onDestroy() with isFinishing() checked, in every situation, my background thread will be handled accordingly?
BONUS question: If my application is killed for some reason (let's say permanently), how can I provide a way for the AsyncTask to save the response anyway? Can I retain an instance of shared preferences in it and write the data in that?
Will onRetainNonConfigurationInstance() be called if my activity is killed due to low memory?
No. Your activity is never individually killed for low memory. Your whole process may be terminated due to low memory, but onRetainNonConfigurationInstance() is only designed for in-process use.
What is the situation (as emphasized by the developer guide) in which onStop() and onDestroy() are not called?
Your process could be terminated due to low memory conditions (onStop() is very likely to still be called, but onDestroy() might not be if Android is in a hurry, such as due to an incoming phone call). Also, your app could crash with an unhandled exception. I am not certain if onDestroy() is called if the user force-stops you, but I doubt it.
All in all, can I be sure that by implementing onRetainNonConfigurationInstance() and onDestroy() with isFinishing() checked, in every situation, my background thread will be handled accordingly?
"Every" is a strong word. If Android terminates your process, your thread is gone as well.
If my application is killed for some reason (let's say permanently), how can I provide a way for the AsyncTask to save the response anyway?
Write the data to disk before doing anything else, and hope you are not killed before that point. Then, next time you run, notice that this saved data is floating around and arrange to do the rest of your work on it.

Categories

Resources