Is it possible that activity lifecycle callbacks get interrupted before executting all its code? can a callback interrupt another?
https://developer.android.com/guide/components/activities/activity-lifecycle
In this documentation it recommends not implementing heavy work in onPause for example as it has a "very brief execution", who controls that? how? does the system calls the next lifecycle callback even if onPause did not finish execution yet?
Docs suggest that onResume()/onPause() execute rapidly for better user experience, because these methods are called frequently. Android activity callbacks are always executed in a sequence. They may be interrupted only by an uncaught exception which will terminate the whole app.
Those calls are what will influence UI mostly (along with onCreate, onCreateView) and if they take a long time to complete their code the user will most certainly know about it.
Say you have this in your onResume() method
OnResume(){ super.onResume; updateView(); }
Something standard, this is what normally happens before the fragment or activity gets “resumed”.
If your updateView(); required 2seconds to complete, weather it’s loading data or creating objects, that’s 2 seconds that the UI is “frozen” and the user cannot use the app, or could mistake as “is broken”
If you have the theoretical same scenario for onPause() then that too is 2 seconds of “frozen” time in the app
It is preferred to have the “updateView()” (essentially your onResume and onPause methods) complete as quickly as possible so that the user does not notice any “lag” in the application.
Related
Do Activity lifecycle callbacks like onCreate(), onStart(), onResume(), always wait for the former to finish before executing, or is it possible that onStart() gets called before onCreate() finishes, interrupts it, and then onCreate continues after onStart() finishes. Is it even possible that they run concurrently, like can onStart() get called while onCreate() hasn't finished, and then a line of onStart() executes, and then a line of onCreate(), and so on.
I assume this isn't the case, and logging on my app shows it isn't, but I haven't ever seen it mentioned explicitely, because I can't know what it's like on other versions, or devices. I also read that each app gets one thread by default, so I think that means that it can't be concurrent, but I wanna make sure.
The main thing that got me thinking about this is the fact that some people online say that in an Activity onCreateOptionsMenu() is called after onCreate() starts but before it finishes. For an example the first answer here. But another user said somewhere else that on some versions onCreateOptionsMenu() is called inside setContentView(), and I guess that's why that is. So does it go something like this then?
onCreate() -> onCreateOptionsMenu() called, onCreate() paused -> onCreateOptionsMenu() finishes -> onCreate() is resumed
Did I get this right? There is no concurrency involved?
And something like this can't happen for the main callbacks like onCreate(), onStart(), onResume()?
You are referencing very old questions/answers regarding the timing of onCreateOptionsMenu(), and these very old posts refer to ActionBarSherlock which was a library that was not part of the Android framework (and may not have followed the rule that I describe below).
As far as I know, all calls to framework methods on Activity or Fragment (unless specifically documented as otherwise) are made on the main (UI) thread. This means that they cannot be interrupted by any other framework calls, that they run to completion and that they cannot run in parallel. My own personal empirical analysis agrees.
Hi I have gone though activity lifecyle on many threads, but I could not find what we should do in onStart, onResume, onPause method of the activity.
In the onStart() method, you add code that's relevant at the beginning of the activity.
Let's say, you have an app that reads the temperature of the device's battery. You'll want to have an initial value, so as to show the user.
So in the onStart(), you'd add code that goes ahead and fetches the information you'd need, and displays it for the user, before your timer (for example) goes and reads the information a minute later.
The onPause() method is called before the application goes in to the background.
To stay with our example, in the onPause() method, you'd save the last recorded temperature to the device; so you can show a comparison when the user next opens the app.
The onResume() method is called when the application is brought back to the foreground (i.e.: you've gone to the task manager, and tapped on your app to show it again).
Again, staying with the going example; in the onResume() method, you'd go ahead, read your saved data, load fresh data, and show a comparison of the two in the application.
Then, when your timer ticks next, only fresh data will be shown.
Your question is a bit vague, so answer might not be super specific..
I would say there are no strict "rules" around what we should do in corresponding activity lifecycle methods.
In fact, you can do nothing there (just make sure you call super method if you decided to override those). I.e. your custom activity might not even override these methods - it will work just fine.
onStart, onResume and onPause methods are just hints to you about activity lifecycle change, so you can react accordingly, i.e. start/stop specific to your activity operations at the appropriate time.
For instance, when onResume is called it means that activity became fully visible to the user, so you might want to start some animation (if necessary)
Again, you are not obligated to put any code in there.
Usually most of the operations are performed within oncreate and onresume.
However for your info let me brief it out,
Onstart- this is called after Oncreate, once activity is visible to the user, if you want to perform some operations before the visibility do it in Oncreate, because most of codes should be operated before user views the activity.
OnResume-Be cautious on Onresume is it is quite tricky it will be called whenever you activity is brought to foreground.
Onpause-Called before Onresume, codes wont be executed here, so strictly avoid adding codes in Onpause instead add inside Onresume.
Hope it helps,
I don't know/understand something about Android callback methods and their implementation.
I have a simple Activity with implemented callbacks like:
#Override
onResume() {
Log.i(TAG, "onPause()");
}
#Override
onDestroy() {
Log.i(TAG, "onDestroy()");
}
onButtonPressed() {
while(true) {
Log.i(TAG, "onButtonPressed()");
SystemClock.sleep(1000);
}
}
When I start my App and change screen orientation I can see onPause() and onDestroy() logs in console.
But, when I press test button (onButtonPressed()) and a long lasting procedure starts (while true) I can see in console only onButtonPressed() logs. I can rotate my phone, and I see that activity is turned according to orientation, but no calls to callbacks onDestroy() and onPause() (no logs in console).
Is my Activity still recreated during orientation change? Why callbacks are not called? Are they called on some other thread?
Can anyone clarify for me this situation and explain how exactly Android performs calls to callback methods?
Tested on AndroidN.
Thank You.
UPDATE:
Looks like it was a mistake from my side.
When I was rotating my phone, I saw that screen is rotating, but haven't understood that activity isn't... It was just placed on one side of screen (sought it was a developer preview bug on Android N). And that confused me :D
Thanks for answer and help.
Unless specified otherwise in documentation all method calls and callbacks are typically handled on the main thread (UI thread).
This goes for all the life cycle methods such as onResume() and onDestroy() in your example as well as UI callbacks such as onButtonPressed().
In the second example where you enter the infinite while loop, you completely tie up the UI thread so none of the life cycle methods can run anymore and the user can no longer interact with the application. This is why when you rotate the device you do not see the log statements being printed. The current Activity is never destroyed and a new Activity cannot be created because you have the thread responsible for doing so in an infinite loop.
This is also why Android documentation recommends moving all long running operations off the UI thread so that you do not negatively impact the user's experience.
I feel like this should have been answered by the documentation in the Activity class, but I'm still not positive -- when is it actually safe to update the UI of an Activity (or a Fragment)? Only when the activity is resumed, or any point between being started and stopped?
For example, the Activity docs state:
The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). During this time the user can see the activity on-screen, though it may not be in the foreground and interacting with the user. Between these two methods you can maintain resources that are needed to show the activity to the user. For example, you can register a BroadcastReceiver in onStart() to monitor for changes that impact your UI, and unregister it in onStop() when the user no longer sees what you are displaying. The onStart() and onStop() methods can be called multiple times, as the activity becomes visible and hidden to the user.
From that reading, I would assume that even if a foreground dialog is displaying, I can safely update UI elements behind it.
EDIT
To clarify: the reason I ask is having been bitten by errors when firing off an AsyncTask, and attempting to update the UI in the onPostExecute method. Even though it runs on the UI thread, the user has navigated away from that view and I would receive an exception. I'm starting a new project now and trying to establish some guidelines around better AsyncTask idioms.
I guess this comes down to what you mean by "safe" to update the UI. For elements on the Activity screen, they can be updated whenever, even if your Activity is not in the foreground (but make sure to update from the UI Thread).
However, the issue that will trip you up is saving state: onSaveInstanceState.
As you may know, the Activity that is in the background may be destroyed by the OS to free up memory. It will then be re-created when you come back to it. During this process, the onSaveInstanceState method will be called. If the OS does destroy the Activity, any changes you made to the UI State after the call to onSaveInstanceState will not be persisted.
For Fragments, you will actually get an IllegalStateException if you try to commit a FragmentTransaction after onSaveInstanceState. More info on that.
To summarize, you can update the UI of your activity at any point and try to gracefully handle the Fragment issues, but you may lose these updates when the Activity is restored.
So, you could say that it is only truly safe to update the Activity while it is in the foreground, or rather, before the call to onSaveInstanceState.
Edit in regards to Async Task onPostExectue
This is likely related to the issue I am referring to above with Fragment State Loss. From the blog post I linked to:
Avoid performing transactions inside asynchronous callback methods. This includes commonly used methods such as AsyncTask#onPostExecute() and LoaderManager.LoaderCallbacks#onLoadFinished(). The problem with performing transactions in these methods is that they have no knowledge of the current state of the Activity lifecycle when they are called. For example, consider the following sequence of events:
An activity executes an AsyncTask.
The user presses the "Home" key, causing the activity's onSaveInstanceState() and onStop() methods to be called.
The AsyncTask completes and onPostExecute() is called, unaware that the Activity has since been stopped.
A FragmentTransaction is committed inside the onPostExecute() method, causing an exception to be thrown.
According to the "Application Fundamentals" article, section "component lifecycle", onResume() is always called when a View becomes active, independent of the previous state.
In the Notepad tutorial, Exercise 3, I have found something confusing in NoteEdit.java:
There is a call to populateFields() in onCreate() as well as in onResume().
Wouldn't it be enough (or even better) to have it only in onResume() ?
In such a small example, it will not do any harm if populateFields() is performed twice, but in a bigger App, things can be different ...
Thanks and Regards,
Markus N.
From a look at Notepad3, I would say you are correct. There doesn't seem to be any reason for them to call populateFields() in both onCreate() and onResume(). onResume is sufficient.
I can see where you need it in both places, if application pauses then you would need it in onResume and if your process gets killed or user navigates back to activity then you will need it in onCreate especially if you are doing some pre-processing.
Per the documentation....for onResume() they recommend using it for lightweight calls unlike in onCreate():
"The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time the activity is in front of all other activities and interacting with the user. An activity can frequently go between the resumed and paused states -- for example when the device goes to sleep, when an activity result is delivered, when a new intent is delivered -- so the code in these methods should be fairly lightweight. "
The Notepad app may want a variable declared if the method was already hit by onCreate not to redo in onResume().