I have some trouble achieving adequate real-time performance from my application and wondering if I've architect-ed it sub-optimally. The requirement is for the application to play a sound and draw a line on a Canvas at a user specified time interval.
I have a Thread that sleeps for the user-specified time interval, wakes up and uses a Handler and Runnable to do the required drawing and sound playback. When I run the application, the beat is steady sometimes, but other times, you can see the effect of GC and random warning conditions from the AudioFlinger.
Is having a Timer thread post back to the GUI thread via Handler/Runnable the best approach? Is there something I can do to bump up the priority of my app while it is visible so that other apps and Android activity are less likely to interrupt it? Do I need to use the NDK to access real-time features not present in the Java API?
It sounds like what you want to have going is a game loop. There are many tutorials out there on creating game loops with more consistant timing that just sleeping, for example simple java android game loop. You might try searching based on that term, see if it helps.
Also when trying to create real time applications (as in constantly dynamic applications not scientific real time system) you would want to avoid to let the garbage collector run. This takes some time and can be perceived as lag. So don't create objects you need to dispose immediately etc.
Related
I am porting over an application that has been written already in C++ to run on Linux that now needs to run on an Android device. It is a GPU intensive app that makes OpenCL calls, running a set of tests. These could take up to several hours or days to finish running.
I have a Java Activity that reads in some basic input, then passes that to the JNI.
It runs fine for shorter operations, but beyond several seconds it will pause; I can unpause it and it will continue to run, but then it hangs heavily every hundred or so operations (taking a minute for what should take less than a second).
Is there something I am lacking in Android knowledge, some critical fallacy I've overlooked that might be causing this? Would it make more sense to move all of the code to a NativeActivity? Or do I just need to make calls back to Java to display something every so often to prevent the OS from shutting me down?
Thanks to any who have the patience to answer my questions
On Android, it is a strong rule that no CPU intensive long operations should run on the UI thread. Neither switching to NativeActivity nor callbacks to display something will not help, but if you run the tests on a worker thread, I might be wise to update the screen from time to time for the user to keep track of the overall progress.
I am rendering objects via OpenGL, and got a nice smooth framerate of 60fps in most situations.
UNTIL I do something heavy in a background thread, like fetching stuff from a REST API, processing it, and adding objects to the graph (low-priority stuff, I care more about UI fluidity). The renderer will then pause for a very long period, up to 1 second (ca. as long as the background thread runs), and then resume as if nothing had happened. I noticed this because an animation is started at the same time, and it gets stuck for this period. The background thread is set to minimum priority, and garbage collection does take up to 100-200ms, but not the whole second. When I set a debug point anywhere in the background task, rendering continues just fine, without any delays.
Is it possible that my heavy background thread starves the OpenGL thread? If so, what can I do?
Of course! A GPU needs to be fed data, and that's done by the CPU. So, if something in the system bottlenecks, like I/O or CPU processing, then the GPU can't get fed. For example, animation is traditionally done on the CPU. This is why you get a lot of games on the PC getting higher frame rates with the same graphic chips but with different CPUs.
I also agree that profiling is a very good idea. If you can, I would suggest profiling to make sure it's actually the REST call, or if the REST call is one of many things
One thing I noticed about REST processing, and this happened to me. Since REST sometimes processes a lot of strings, and if you don't use StringBuilder, you can end up firing off a lot of garbage collection. However, it doesn't sound like you are getting this.
I've been doing several opengl based games for Android recently,
and there's one issue I can't find a way to get rid of.
When system starts some process in background (checking CDMA status, updating an app, or prerry much anything else), the game suffers a whole second stutter. Once in every few minutes. It was an annoying issue, until I started a breakout-style game, which is completely wrecked by that stutter (the ball teleport right through bricks).
It there a way to give the game activity priority over background processes, or pause all those background updates and installs while the game is running?
It there a way to give the game activity priority over background processes
The game activity already has "priority over background processes", to the extent that it can. Generally, background processes run in a class that limits their CPU utilization.
Note that Android's performance in this area has improved over the years. Your symptoms feel like what I would expect from an Android 1.5 device, for example.
or pause all those background updates and installs while the game is running?
No, sorry.
In the Android examples, like LunarLander, and many other tutorials written on blogs across the net, game loops almost always run a separate thread to call the state updating and rendering parts of the game.
Why is this? What are the advantages and disadvantages? The only reason I can think of is just to keep the app responsive to input such as if the user presses the menu or back buttons. Other than that, the game just has to chug along in update/render cycles as fast as it can.
I'm aware this is a good reason, although one would hope that if one's game is running at a decent frame rate, the app would remain responsive enough. But, are there any other reasons?
On the other hand, I imagine it would create more headache accessing game resources, for example a game object manager or the sound system, which may live on a separate thread.
On Lunar lander and other android apps - it is important to have your surface view run on a separate thread, so that the android OS does not kill it for any long running processes.
Android keeps the main UI thread - used for the menu and home buttons among other things - avaiable to recveive user input at all times. If you app causes the main thread to slow down, the OS will kill your thread and end you game.
So running your game loop off of the Surface View thread lets you game run as fast as it can when it has focus, but it also makes it possible for android to interrupt it whenever it needs to, for instance when a call come in, or the user presses the home button.
I have a game out on Android, and it runs in a single thread. Performs the work in run() and the draws in onDraw(). Pretty simple.
However, on a Droid it runs much faster than on a G1.
What is a best practice for ensuring that the game runs at the same speed regardless of the device?
This is typically controlled by the combination of using a "game loop" ( http://gamedesign.wikicomplete.info/game-loop ) where the code loops around and draws frames with a timed interval. When using different devices, frames may take longer to draw so this is typically dealt with by either dynamically adjusting the "level of detail" (LOD) and/or using "frame skipping" whereby you don't draw a frame every loop. In fact there's another question that demos a basic algorithm for this:
Allegro 5 game: game loop that runs at constant speed?
-Oisin
Running faster is usually a good thing! The best way for ensuring the game runs correctly on any device is to base your updates on the time passed since last update. This keeps the game feeling consistent when running on a faster device.
Otherwise you could add a sleep call on the faster device - but why not run smoother when you can.