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.
Related
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.
I need some confirmation on some information I just found out recently.
Are the lifecycle methods onCreate(), onStart() and onResume() handled together as ONE message in the message queue during an orientation change?
and on the flip side is onPause(), onStop() and onDestroy() handled together as one message?
One of the reasons I wanted to know is that if I have a thread that loops infinitely while posting to the main ui thread and I change my orientation, will it always post after onResume()? It will never post BETWEEN a lifecycle method right?:
private static class MyThread extends Thread {
#Override
public void run() {
while (true) {
mainUiHandler.post(myRunnable);
}
}
}
Thanks!
No. At least not as something you can rely on. Remember that onPause can be called without onStop in some cases. Same for onStart without onResume. (in both cases they'll be called eventually if needed). onDestroy may never be called at all, your app should be written assuming that it won't be for sure.
If Java provides Garbage Collection, then what is the need of onDestroy() in Activity Lifecycle?
onDestroy: The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space.
Here is an example......
public void onDestroy() {
super.onDestroy();
}
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. Here is a good article that I recommend people to read that relates to creating an exit button. While it's not exactly what you asked about, the concepts will help you understand what's going on.
You can use onDestroy() to finalise the program. I have used it in the code bellow to tell the server that the client is closing its socket to the server so I can notify the user on the server end that the client has disconnected.
client:
...
protected void onDestroy(){
super.onDestroy();
if(connected) {
clientMessage.println("exit");
clientMessage.close();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
finish();
}
...
server:
...
while (connected) {
input = clientMessage.readLine();
if ("exit".equals(input)){
break;
}
...
}
...
onDestroy() is a method called by the framework when your activity is closing down. It is called to allow your activity to do any shut-down operations it may wish to do. The method doesn't really have anything to do with garbage collection (although your shut-down operations—if any—might involve releasing additional resources that can be gc'ed). In particular, it has nothing to do with C++ destuctors (despite its name).
If you have no shut-down operations to do, you don't need to override it. The base class does essentially nothing.
onDestroy may be called when an activity is destroyed, but you can not count on it. 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.
See: http://developer.android.com/reference/android/app/Activity.html#onDestroy()
In the Android Activity Lifecycle's onDestroy docs:
onDestroy() is called before the activity is destroyed. The system
invokes this callback either because:
the activity is finishing (due to the user completely dismissing the activity or due to finish() being called on the activity), or the
system is temporarily destroying the activity due to a configuration change (such as device rotation or multi-window mode)
The Activity#onDestroy() API docs also answers it quite well:
This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. source
As the quote from the docs say, its for preventing a destroyed activity leaving things around (e.g. memory leaks through referencing, threads), but only when the rest of the app still runs. If the application process ends, it doesn't matter if you forget to clean up threads or other resources since the OS will do it for you. You don't need to override onDestroy.
There is no need to do what sam786 is doing (overriding and just calling the super method) as that is absolutely useless. All other answers seem to go along the lines of "clean up", but don't explain what kind of clean-up or when. You should not be saving any data in onDestroy(), as you can't guarantee it will be called, so you will lose data sometimes. It won't be called when you press the home button, for example (the case where you want data to be saved).
The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed
Article Exit Button in Android
It gives your program a chance to do things like cleanup resources (say threads) so that they don't pollute the associated application. If you don't have any use for it, then don't override it.
See:onDestroy()-Android Reference
Specifically, if I have a method running in my Activity class, then when the phone goes to sleep (CPU off), will the method run to completion before onPause() is called?
class MyActivity extends Activity {
...
public void doSomeWork() {
...
... // <-- Device goes to sleep at this point in time
...
return; // Do we get here before onPause() is called?
}
...
#Override
public void onPause() {
...
}
...
}
In addition to Activities, will a running thread (perhaps launched by an Activity class) be interrupted at whatever line of code it's at when the device goes to sleep? I see contradicting answers in this post: Does a Thread launched by Activity continue running once the device goes to sleep?
Going further, I understand that the Activity's onResume() will be invoked when the device wakes up; if doSomeWork() above or the aforementioned thread was indeed interrupted midway when going to sleep, will the remaining code resume?
Thanks in advance for any insight.
It's considered to be a good Android practice not to run long tasks on the main UI thread, therefore your doSomeWork() is supposed to finish within a few hundred milliseconds and reach return statement before onPause() is called.
Regarding doSomeWork() interrupted midway -- the only possibility of this to happen is when your application shows the dreaded ANR dialog and force closes, so you should not be concerned about restarting it halfway through.
Here when you move out of the activity or a pop up comes to your activity like a phone call appears or you rotate your screen on Pause is called.
The link provided by you talks about AsyncTask. AsyncTask is a thread that runs background and updates UI after fetching some data, During the process if the user rotates the phone Android kills the activity and recreates if the thread is linked to the activity then your activity will not be killed but leaks out.
If you need more details on AsyncTask & activity you can read this
Is AsyncTask really conceptually flawed or am I just missing something?
I have a game using OpenGL. I've built off of the examples, for the most part, having the Main Thread, Renderer Thread (GLSurfaceView.Renderer) and added a GameLogic thread as well. When the game is executed, everything seems to run through perfectly. When back is pressed and onPause() is fired, I'm also firing the GLSurfaceView()'s onPause, but I'm having a "crash" at that point. Here's the MainActivity's onPause:
#Override
protected void onPause() {
Log.d("Main", "Pre- Super onPause");
super.onPause();
Log.d("Main", "Post- Super onPause");
mGSGLView.onPause();
Log.d("Main", "Post- GL onPause");
}
Each log point is reached except the last. In logcat, immediately following the "Post Super onPause" line, I get an Activity pause timeout.
I am not overriding onPause in the GLSurfaceView class... and as far as I know this had been working for me for some time, but recently started occurring when I started getting a completely black screen on the second time I tried to run my game which sits until finally getting an ANR. 95% of my game runs natively. Similar to the San Angeles example, the Renderer calls to onDraw, for instance call a NativeDraw function instead of java. The same is true for the onSurfaceCreated, onSurfaceChanged, and I also call a native GameLogic method in the logic thread (basically all that is called there is a thread sleep and that logic method.)
I hope I've given enough information, please let me know if there is anything else I should be providing.
EDIT - Well... I've actually narrowed down the issue to a native function call where I'm freeing certain pointers that had previously had memory allocated for them with malloc(). My code there looks okay, but if I omit the call, everything works okay, so my free() calls must be corrupting something...
Okay, I'm only answering this myself because the solution was so specific to my own code that no one would have been able to.
If you have memory allocated on the native side, take care not to free it until after you are sure no other code will be trying to access it.