This post shows an empty basic game loop in Android, similar to how we used to make game loops on the J2ME platform.

The View implements Runnable and starts a render thread itself. An interesting thing is that we can’t invalidate the View from its own thread, as invalidate must be called from the main UI thread only. Instead we use postInvalidate which sends a message to the UI thread’s message queue. The consequences are that drawing is not performed immediately, but only when the UI thread handles the message.

Activity

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.test.drawcanvas;

import android.app.Activity;
import android.os.Bundle;

public class DrawCanvas extends Activity
{
    private static DrawView mDrawView = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);        
        mDrawView = new DrawView(this);
        setContentView(mDrawView);
    }
    
    @Override
    public void onResume()
    {
        super.onResume();
        mDrawView.start();
    }

    @Override
    public void onPause()
    {
        super.onPause();
        mDrawView.stop();
    }
}

View

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.test.drawcanvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.View;

public class DrawView extends View implements Runnable
{
    public boolean isRunning = false;
    private Context mContext = null;    
    private Thread drawThread = null;   
    private Drawable mIcon = null;
    private int mIconX = 0;
    private int mIconY = 0;
    
    public DrawView(Context context)
    {
        super(context);
        mContext = context;
        mIcon = context.getResources().getDrawable(R.drawable.icon);
    } 
    
    @Override
    protected void onDraw(Canvas canvas)
    {
        mIcon.setBounds(mIconX, m.IconY, mIconX+48, m.IconY+48);
        mIcon.draw(canvas);         
    }
    
    public void start()
    {
        isRunning = true;
        if(drawThread == null)
            drawThread = new Thread(this);
        drawThread.start();
    }    
        
    public void stop()
    {
        isRunning = false;
        drawThread = null;
    }    
    
    private void update()
    {
        mIconX++;
        mIconY++;
    }

    public void run()
    {
        while(isRunning)
        {
            try
            {
                update();
                postInvalidate();
                drawThread.sleep(20);
            }
            catch(InterruptedException ie) {}
        }
    }
}