Fixing the Lunar Lander example: a threaded gameloop for Android

Recently I am very interested in creating a small game for Android. Since every game needs a proper working gameloop and a underlying drawing mechanism I started to look at some examples from the internet. My first attempt in searching a good example lead me to the Android Developers page. There is a good description on how to get started with 2D graphics. I decided to take the threaded aproach as described there. This means that there is a thread that draws everything into the view as fast as possible while not blocking the UI thread.

Some further poking on the Android Developers page lead me to the Lunar Lander example which looked right what I wanted to do. I installed it on my HTC and played around with it a bit when I suddenly received this error message:

What happened? To put it simple, there is a bug in Google’s Lunar Lander example. Let’s look at the implemenation of the thread that draws the game in LunarView.java and how it’s started:

1
2
3
4
public void surfaceCreated(SurfaceHolder holder) {
	thread.setRunning(true);
	thread.start();
}

The method surfaceCreated() is a callback method from the SurfaceHolder class. It is called whenever the Surface we want to draw on is created, for example when the application starts or when we return from a pause. Respectivly the method surfaceDestroyed() is called whenever the surface is destroyed, for example when the application terminates or another application gets the focus.

1
2
3
4
5
6
7
8
9
10
11
public void surfaceDestroyed(SurfaceHolder holder) {
	boolean retry = true;
	thread.setRunning(false);
	while (retry) {
		try {
			thread.join();
			retry = false;
		} catch (InterruptedException e) {
		}
	}
}

In the Lunar Lander implemention the drawing thread is terminated on the first time the surface is destroyed. If we then try to come back to the application, for example with a long click on the home button, the application throws this exception:

java.lang.IllegalThreadStateException: Thread already started.

We reached an illegal state because a thread is only allowed to be started a single time!

To fix this issue I don’t stop the drawing thread in my application if the app looses focus. Instead I just stop drawing and let the thread sleep for a while (and thus save the CPU resources etc). When the app gets focus again, the drawing starts over. In the example below this behaviour is controlled by the paused variable, running is the variable that is set to true when the game starts and is set to false when the app is terminated and the thread really needs to stop:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public void run() {
	while (running) {
		while (paused) {
			try {
				Thread.sleep(50L);
			} catch (InterruptedException ignore) {
			}
		}
 
		Canvas canvas = null;
		try {
			canvas = holder.lockCanvas(null);
			draw(canvas);
		} finally {
			if (canvas != null) {
				holder.unlockCanvasAndPost(canvas);
			}
		}
	}
}

I’ve implemented this gameloop in a small example that displays Conway’s Game of Life:

Of course my implementation has a fixed timestep as suggested by the famous article Fix Your Timestep!

Download my example sourcecode here: android-gameloop-example-v1.zip
App in the Android Market: Gameloop Tutorial

4 thoughts on “Fixing the Lunar Lander example: a threaded gameloop for Android

  1. Very nice read and good job fixing the example ;-D!

    Where and how is the variable paused controlled? Is there some kind of callback being called when the app is paused (e.g. as soon as one switches to the home screen)?

  2. Thanks Martin ;)

    The pause variable is set (and unset) by the same callbacks as in the Lunar Lander example: surfaceCreated() and surfaceDestroyed(). Only this time I don’t stop the thread completly, just put it in “idle”.

  3. I see.

    Other question: how did you debug / find the offending lines in the first place? Are there any tools available for Android?

  4. Since the code is available, I just checked out the project, set some breakpoints and connected the debugger to my phone. With the Android plugin for eclipse this is just a matter of seconds! The plugin is really good, you really should have a look at it. There is a Google talk about the Android development tools from this years Google IO:

Leave a Reply