When to call GLSurfaceView methods onPause() and onResume() - android

I have repeatedly read that onPause() and onResume() must be called for the GLSurfaceview during the onPause() and onResume() methods of the enclosing activity. I gather that this is to stop and restart the rendering thread to save resources. However, when I log each iteration of the onDraw method of the rendering thread, I see that onDraw stops being called when I press the home or back buttons, and when I return to the app, onSurfaceCreated and onSurfaceChanged get called, and then the onDraw call resume - even after I remove the calls to the GLSurfaceview's onPause() and onResume() methods in the corresponding activity methods. If the rendering thread is not being stopped, how am I seeing this behavior? Is the rendering thread still somehow alive even though onDraw is no longer being called? And if the rendering thread is being shut down automatically when the activity loses focus, then why is it necessary to call the GLSurfaceview versions of onPause() and onResume()?

It seems like a bug in GLSurfaceView where it tries to be clever by tolerating you forgetting to call onResume() and onPause(). I'm not sure if this is deliberate or not.
Leaving the calls out works almost always, but it can cause odd behaviour and crashes in some situations. I'm not exactly sure what those situations are, but I have traced a few weird crashes back to missing onResume()/onPause() calls. Something gets slightly messed up with the state machine in GLSurfaceView when you don't call them - it looks like the fallback logic to 'automatically' resume and pause doesn't get triggered in 100% of cases.

Related

Android callback methods: When? How? From wheech Thread?

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.

onPause() gets called on my activity. Then, when brought back to the top, onResume() never gets called

After the onPause() getting called, there are no calls to onStop() nor onDestroy(). The application is still running, and pid is the same (if I check it using "ps" Linux command). When the activity gets back on top, there are no calls to onCreate() nor onResume(). The app appears to be hanging. And after a while messages in the log appear saying "Activity destroy timeout for ActivityRecord". Oh, and it does not all the time. I can run it without getting stuck 2-3 times (with onStop() and onDestroy() called after onPause(), and the new activity getting created when it's time to get on top). But eventually I get the situation described in the title.
Any idea how this could happen? Many thanks :)
Well, the app was actually hanging in the state "after onPause() called and complete", waiting for a (not properly initialized) mutex while trying to handle an external event. The big part of the apps data was destroyed during onPause(), including that mutex.

Why is onDestroy() called after onResume() when using back-button

When I start my android-activity first onCreate() is called, then onResume().
When I then press the back-button to return to the home-screen and tap the app-icon again, first onCreate() is called, then onResume() and then onDestroy().
My app is still active then, but doing some action result in error since onDestroy() sets a few members to null.
Why is that?
Update: When I wait 30 seconds after pressing back everything works fine. I'm not doing anything heavy in onDestroy except setting a few variables to null and .interrupt()ing a background-thread.
Figured this out by myself. My understanding of what an Activity is was flawed. Of course Android calls onDestroy() on the old Activity instance, which can happen several seconds after the new one has been constructed.
onDestroy gets called because, by default, pressing back key results in your activity calling finish() which initiates the destroying of the activity which calls onDestroy().
To prevent doing some action in case the activity is being destroyed do like this:
if(!isFinishing()) {
// do your action here
}
isFinishing is a method of the Activity.
are you doing some heavy operations in onDestroy(). I think your activity view is destroyed, but not the activity object. And you tap on the App icon even before the previous Activity object is actually destroyed.
I think there is something in addition to what you are describing. Android doesn't just keep activity from being destroyed, something MUST be happening on the main thread.
The symptoms sound exactly as if you had either:
a service doing a longish HTTP or database operation. Are you sure there are no suxg things?
another thread (perhaps managed by an AsyncTask?) calling a synchronized method

Is it safe to deallocate resources in onStop()?

Hi All!
I have an Activity which allocates quite lot of memory while it shows a visible layout. The UI heavily depends on this memory, however, there is no need to keep these allocations after the user traverses away from the Activity (usually by bringing another Activity to focus).
The Activity starts to allocate memory in onResume() and all is fine with that. It's the deallocation that confuses me a bit, though. As of now I release all memory in onPause() which also destroys the corresponding UI elements. Since the Activity is still visible while running onPause() the user will see the actual UI elements becoming destroyed. This is ugly and not what I want.
So my question:
Is it safe to release memory (destroy UI) in onStop() (according to documentation the Activity is not visible when onStop() is called)?
Is onStop() reliable?
Is onStop() guaranteed to be called every time when onPause() is called?
Edit:
I feel I must explain a bit more clearly what confuses me. According to developer.android.com:
...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...
The onStop() method is marked as "killable".
Does the above mean (especially the "after that method returns" part) that the entire scope of onStop() is guaranteed to run, but once it returns nothing else is guaranteed any runtime (e.g. a spawned thread started in onStop())?
Or does it mean that onStop() might get interrupted even before it reaches the end of its scope (as of the killed at any time part)?
Or does it mean something else that I - in my divine stupidity - don't see.
The difference is that the activity sees to it that onPause should finish executing first before "destroying" the view, while onStop is a lifecycle stage that follows after the view is already in the background - meaning the activity is not visible anymore.
doing things inside onPause makes sure that the items you need to save are still intact before letting go of them - for example you need to save the text in your EditText, or the on/off position of RadioButtons, etc.
deallocation however doesn't need any of these things anymore, so it should be fine if you do it in your onStop
onStop() should be safe and reliable enogh for your purpose.
"Guaranteed" is relative in this case, given that your activity may be killed without any notification. But in that case your memory resources are released anyway.
it's as safe as anything else? Worse comes to worse your app will be killed with onDestroy. In mobile development, you basically have to assume that at any given moment your app could be killed.
It's been reliable for me in releasing media objects for a while now.
Not really guaranteed, as sometimes onDestroy is called depending on what's going on.
No, it is not safe as only onPause() is guaranted to be called. onPause() means that yor activity loses focus - perfect place to give away not necessary resources

Activity pause timeout after calling GLSurfaceView.onPause()

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.

Categories

Resources