I am using this for some signal processing. It all works fine except when the screen goes off and the display was rotated at the time. Normally screen off just produces an Activity onPause(), but when the screen is rotated it goes: onPause(), onStop(), onDestroy(), onCreate(), onStart(), onResume(), onPause(). Ie it appears that Android 'unrotates' the screen first.
Unfortunately this seems to make AudioRecord crash or freeze in some unknown way.
The basic way I have it all operating is that in the onResume() a new thread is started and this instantiates an AudioRecord instance, sets it up, starts recording and then sits in a loop:
keepProcessing = true;
while (keepProcessing)
// read a block of data and process
In the onPause() in the UI thread keepProcessing (a volatile variable) is cleared, and it then waits for the worker thread to stop.
if (thread.isAlive()) {
keepProcessing = false;
thread.join();
}
thread = null;
When the other thread drops out of the keepProcessing loop it stops recording, releases the AudioRecord resources, drops the AudioRecord instance and terminates.
As a general start / stop mechanism this all works fine. Checking with breakpoints and adb everything seems to happen in the right order. It just doesn't work in this screen rotated scenario. I can only think it is because of the very rapid new Activity onCreate() etc after everything stops in the old Activity. Ie there is something in the AudioRecord that is still busy. What happens is everything freezes up when one tries to turn the screen on again.
If I dummy the AudioRecord code so that it doesn't actually start recording, the loop just sits and sleeps, and then doesn't stop recording again, it is all OK. It only goes wrong once the recorder has gone into recording mode.
Any advice?
When you rotate the device, your activity is actually stopped and destroyed. If you have background threads doing work, this totally screws you over. The best way to fix it is to tell Android not to do that, by adding android:configChange="orientation" to your manifest for that activity. Yeah, it's a bad architectural decision by Google and annoying to the point where I almost suggest adding that for all activities.
Yes, I can see that, and I've just found what was happening, which was sort of that.
Owing to an error where the keepProcessing flag was initialised, there was a race condition that could leave the background thread running when the Activity stopped.
"If you have background threads doing work [when the activity stops], this totally screws you over"
You are dead right. It does.
Related
When creating a SurfaceView it's normal to also create a separate thread to draw onto the surface. Is it better programming practice to have the thread be created and destroyed at the same time the activity is, or at the same time the surface is?
What are some of the advantages/pitfalls of either way?
The Activity and the View are created at essentially the same time. The Surface is created later, and that's what the SufaceHolder callbacks are for.
You can't render on the Surface before it exists or after it's destroyed, so there's no point in starting your rendering thread before then or leaving it running after. The tricky part is that the callbacks happen on the main UI thread (since that's where you set it up), so the surfaceDestroyed() callback could be called while your render thread is doing work.
EDIT:
Some notes about the SurfaceView / Activity lifecycle are included below. These are now part of the official Android documentation; see Appendix B in the System-Level Graphics doc. The original post is available below for historical purposes.
You can see examples of both approaches in Grafika. Approach #1 (create/destroy thread in onResume/onPause) can be seen in TextureFromCameraActivity, approach #2 (create/destroy thread in surfaceCreated/surfaceDestroyed) can be seen in HardwareScalerActivity and RecordFBOActivity.
A few thoughts about app life cycle and SurfaceView.
There are two somewhat independent things going on:
Application onCreate / onResume / onPause
Surface created / changed / destroyed
When the Activity starts, you get callbacks in this order:
onCreate
onResume
surfaceCreated
surfaceChanged
If you hit "back", you get:
onPause
surfaceDestroyed (called just before the Surface goes away)
If you rotate the screen, the Activity is torn down and recreated, so you get
the full cycle. (You can tell it's a "quick" restart by checking isFinishing().) It might be possible to start / stop an activity so quickly that surfaceCreated() might happen after onPause(), but I'm not sure about that.
If you tap the power button to blank the screen, however, you only get onPause() --
no surfaceDestroyed(). The Surface remains alive, and rendering can continue (you
even keep getting Choreographer events if you continue to request them). If you have
a lock screen that forces a specific orientation your Activity can get kicked, but
if not you can come out of screen-blank with the same Surface you had before.
This raises a fundamental question when using a separate renderer thread with
SurfaceView: should the lifespan of the thread be tied to the Surface or to the
Activity? The answer is: it depends on what you want to have happen when the screen
goes blank. There are two basic approaches: (1) start/stop the thread on Activity
start/stop; (2) start/stop the thread on Surface create/destroy.
#1 interacts well with the app lifecycle. We start the renderer thread in onResume() and
stop it in onPause(). It gets a bit awkward when creating and configuring the thread
because sometimes the Surface will already exist and sometimes it won't. We can't simply
forward the Surface callbacks to the thread, because they won't fire again if the
Surface already exists. So we need to query or cache the Surface state, and forward it
to the renderer thread. Note we have to be a little careful here passing objects between
threads -- best to pass the Surface or SurfaceHolder through a Handler message, rather
than just stuffing it into the thread, to avoid issues on multi-core systems (cf.
Android SMP Primer).
#2 has a certain appeal because the Surface and the renderer are logically intertwined.
We start the thread after the Surface has been created, which avoids the inter-thread
communication concerns. Surface created / changed messages are simply forwarded. We
need to make sure rendering stops when the screen goes blank, and resumes when it
un-blanks; this could be a simple matter of telling Choreographer to stop invoking the
frame draw callback. Our onResume() will need to resume the callbacks if and only if
the renderer thread is running. It may not be so trivial though -- if we animate based
on elapsed time between frames, we could have a very large gap when the next event
arrives, so an explicit pause/resume message may be desirable.
The above is primarily concerned with how the renderer thread is configured and whether
it's executing. A related concern is extracting state from the thread when the
Activity is killed (in onPause() or onSaveInstanceState()). Approach #1 will work
best for that, because once the renderer thread has been joined its state can be
accessed without synchronization primitives.
I am experiencing a very strange phenomenon (test device: HTC Desire HD, Android 2.3.5). I know that System.gc() is needless and discouraged, and I don't try to suggest otherwise, but the point is that it shouldn't cause issues either (i.e. it should be useless at most).
I have an application which contains a GLSurfaceView in its view hierarchy. The GLSurfaceView is instantiated and added in the Activity.onCreate(). Normally, the application works like this:
User starts the app and goes to mainmenu
User chooses a mainmenu item which sets the GLSurfaceView to View.VISIBLE
User plays with the in-built game on GLSurfaceView
User goes to mainmenu and exits the activity (=> Activity.finish() is called)
My Activity.onPause() looks like this:
mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread
So far so good, everything works fine. However, issues appear after I add the following code to onPause() (for the case when the user exits the game from the mainmenu):
mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread
if (isFinishing()) {
System.gc();
}
In details: if the Activity is started for the first time (= i.e. the app process didn't exist before), everything works fine. However, starting from the 2nd start of the activity (= after the first exit from the mainmenu, i.e. after the first Activity.finish()), the framerate of GLSurfaceView is reduced by 40-50%, the in-built game becomes slow.
If I remove the System.gc() call, the problem disappears. Moreover, if I do the following, it also gets rid of the problem:
mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread
if (isFinishing()) {
// 1. get layout root of View hierarchy
// 2. recursively remove (detach) all Views
// 3. call GC
System.gc();
}
I didn't add concrete code because it's complex, so I used comments. If I just detach the GLSurfaceView via removeView(), it is not enough. The entire view hierarchy needs to be cleared.
Note that I couldn't find any memory leaks (no Activity leak via drawables/statics etc.). Moreover, of course, the gameThread properly exits when the app is closed (I just didn't include its source code).
Any ideas, guesses? Apparently, System.gc() seems to cause some issues for the Activity/layout destroying mechanism of Android. Again, as I said, if I remove System.gc(), the problem disappears.
I have experience of Android Game Programming. I used to clear all the view in hierarchy because when running threads if you call System.gc() sometimes it happens that your thread has a reference to some of your view, even if you call system.gc() this view won't get removed and if you keep playing again and again this game you will notice that your heap memory is started growing.
It depends upon the memory leak, if you are leaking some KB memory it will take more time to crash your game. The best way it to use Eclipse Memory Anlyser (Eclipse MAT) and compare your stacks.
Step1:
take memory snap shot when you start your game for first time
Step2:
take memory snap shot when you start your game second time
Step3:
Now compare your both stacks of snapshots it will tell you the difference.
It is a very useful tool. I was having huge memory issues in my game Apache Attack. I fixed them using this awesome tool.
Follow this ECLIPSE MAT TUTORIAL
I am trying to handle problems that occur in my application when the phone is plugged into certain types of chargers and put into "Car Mode" or "Driving Mode".
In the running application, onDestroy() is called and immediately followed by onCreate(), and the application starts again normally. However, subsequent calls to update UI elements (in the newly created main Activity) now have no effect, and it looks like I've lost scope on my layout.
RelativeLayout splash = (RelativeLayout) findViewById(R.id.splash);
splash.setVisibility(View.VISIBLE);
What could be ocurring onDestroy() that I'm not accounting for? I don't do much cleanup onDestroy because I didn't think I needed to.
The Activity has been detached from the UI by the time onDestroy() is called so having UI calls to it doesn't make any sense. If you need the splash to be shown, set it to View.VISIBLE in onCreate(), onResume(), or maybe onPause(). I'm not entirely sure if onPause() would act any different.
When the phone rotates the activity is destroyed and recreated. Plugging into a car charger usually forces the phone to landscape mode, thus rotating it (from portrait, most likely) and calling onDestroy. There is a way to prevent this behavior with some activity flags -- but Google advises against it.
We need to see some more code for this Activity to figure out what's going on.
Also, as DeeV points out, the activity is long gone by the time onDestroy gets called, so it might not be the right place to be doing whatever it is that you're doing -- but we need more code to be sure.
As a sidenote, sliding the keyboard up (on phone's that have slideout keyboards) will produce the same effect.
I have been searching for an answer to this and while I can find others who have been seeing the same entries in the log cat none of the footprints seem to be similar to mine.
Basically I start an infinitely repeating animation as part of my activity start up. The screen is rendered properly, is responsive to all touch input but I get the following entries in my logcat:
08-17 16:03:25.910: WARN/ActivityManager(110): Launch timeout has expired, giving up wake lock!
08-17 16:03:25.972: WARN/ActivityManager(110): Activity idle timeout for HistoryRecord{4057ad58 com.companyname.dm/.ui.activities.home.HomeActivity}
I have read posts that state these entries are indeed just warnings to indicate the main thread looper has never become idle and not a problem if it is the intended mode of operation. However, besides that fact that it seems excessive that the small repeating animation (a scale/transform/alpha animation that repeats every 3 seconds) is filling the message queue, my main issue is that it is preventing the ability to create automated tests. We are trying to implement a test using robotium but the test will never start because of the idle timeout.
Not starting the animation will eliminate this problem, but is much more a workaround than a root cause solution. I am trying to understand if I am either not implementing my animations properly, if this is indeed just the expected behavior or if there is a way to ensure the connection the instrumentation/robotium will be established.
Any insight would be greatly appreciated! Thanks.
Try starting your animation in a new thread, if you do too much stuff in the onCreate method you will block the UI-thread in Android, and it could possibly lead to an ANR (Application not responding) if you take longer than 5 seconds before returning. By starting your animation in a new thread the onCreate will return and the system will be happy.
new Thread(new Runnable() {
public void run() {
//start animation.
}
}.start();
The code which is repainting to the screen need to be started in a different thread, else the main UI thread will never become idle, which is causing the problem.
You may have issues when interacting with the UI from another thread, for this you should look into AsyncTask which is actually what is used to compute/draw progress bars. The obscene number of warnings is most likely because the warnings are generated any time after X seconds, which is only limited by Android's checks.
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.