It makes sense that Android, by default, leaves the volume controls to change the ringer volume. Not all apps play sounds or videos so it'll be annoying to press home every time you want to change the volume.
However, if your app plays sounds at irregular intervals then you'd notice that the volume can only be controlled while they are playing.
So how can you change the volume of the sound effects while you're in the app? Amazingly, it involves no overriding of event listeners for buttons or implementing of listeners.
During your Activity.onCreate() call, simply add this magical one liner: this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
That's it! Now the volume buttons will behave.
I could not find that in the documentation for the life of me, but it was scattered across a few StackOverflow questions.

This magical one liner will leave you feeling awesome, just like Kim Jong Il Beiber.

Django's syndication library works pretty well, it's easy to extend and use, but caching is another story.

Because you don't have access to the view, you can't use fragmented template caching.

Because the Feed class is not a view, we're a bit stuck on that too.

Luckily the class is "callable", meaning we can catch it as it's called.

class YourFeed(Feed): def __call__(self, request, *args, **kwargs): # Cache the RSS feed # It has to be done this way because the Feed class is a callable, not a view. cache_key = self.get_cache_key(*args, **kwargs) response = cache.get(cache_key)

Run your application as normal and then exit. It'll run a little slower than usual, but that's OK because the results we're after are given in percentages.

Retrieving the trace file

Using the Android SDK, you should have access to "adb" and "traceview".

Using ADB, you can extract the file from the emulator using:

adb pull /sdcard/traceFile.trace C:\trace\

This will download and save the file to C:\trace\traceFile.trace

Using traceview.bat, type:

traceview C:\trace\traceFile.trace

Note: you need to specify the full pathname.

This will start the Traceview program.

Reading the trace data

Jibberish? Certainly not!

The bars at the top help you visualise the CPU time which each thread consumes.

The tree list at the bottom indicates which functions are called, ordered by the amount of processing time it takes.

You can see that GameCanvasView:DrawThread.run() is eating a whopping 70% of the CPU time. That's ok, because it's a game which redraws often and encompasses the 2 chunky functions in spot #2 and #3, GameCanvasView.onDraw() and GameCanvasView.drawScoreboard().

Wait, drawScoreboard() is #3? Why? It's only being shown for about 4 seconds at the end! Why is it using up so much CPU?

Wow, ScoreboardData.draw() is #4, using 38.2% of the CPU draw time. Something just isn't right.

Expading the ScoreboardData.draw() tree shows some interesting information. It shows that String.format() is proving to be VERY expensive in the display process.

That explains why the rest of the Traceview screenshot showed mainly java.lang.String and java.util.Formatter functions.

Once the game ends, I built the Strings in gameFinished() and only read them in the display. This dramatically improved the rendering speed of the scoreboard!

This was the end result. I forgot to take an intermediate screenshot.

After performing another trace, the call to drawScoreboard() dropped off the first page of the Traceview to below 4.8%, along with all the java.lang.String and java.util.Formatter methods.

Such a simple change and the results above show it's well worth it! I also took the time to make a few other changes around the place with similar design patterns.

Only initialise when you need to

Another method called by onDraw(), drawHud(), was eating up 17% CPU. This method simply displays the bar indicating how much time was left.

In that method, I was initialising Rect objects over and over and giving them the same values. Those values could have been determined when the View was created, so I moved them out of the draw loop and set them once.

After the simple change, it dropped to 5.0% CPU usage.

Avoid internal use of get/set methods

This is straight off the Android documentation. They're expensive and you'd rather be using the variables directly rather than through a get/set method.

I've personally extended this tip a bit more. Although frowned upon in the encapsulation world, I've declared more class variables to be public than I should rather than forcing external classes to go through getter and setter methods.

Remove defensive code once your app is grown up

Initially, my BitmapCache was a bit experimental. I wrote defensive code in case the test cases failed so I had some sort of fallback in debugging.

Sources

When trying a different approach to controlling the onDraw() timing in my app, I stumbled upon a little roadblock which was not mentioned in the documentation.

I tried to use postInvalidateDelayed() to control the amount of time it took for the next redraw to happen, but for some reason it seemed to be ignored. I've even tried all invalidate(), postInvalidate() and postInvalidateDelayed() with threading.

invalidate() had to be called in the UI thread, however postInvalidate() and postInvalidateDelayed() could be called from any thread.

The reason is the SurfaceView class calls the setWillNotDraw() method to prevent the normal drawing methods of the View class.

That method has to be called in the UI thread, however it cannot be called in the constructor as the Surface has not yet been created.

You should call setWillNotDraw(false) during the surfaceCreated() stage of initialisation. Doing that, you sacrifice a bit of performance that the SurfaceView offers.

If you'd rather wait for a specific time to disable the SurfaceView custom drawing, use an AsyncTask.