Arduino Uno

Header

Corner

Threaded drawings :: Continously

The here explained approach repaints the drawing surface continuously as fast as the GPU can handle it.

First of all, we need to create a class that extends the SurfaceView class. I named it DrawSurface.

package lu.fisch.template;

import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class DrawSurface extends SurfaceView implements SurfaceHolder.Callback {

	// a reference to the drawing thread
	private DrawThread drawThread = null;
	
	// your application certainly needs some data model
	private Object dataModel;
	
	public DrawSurface(Context context) {
		super(context);
		init(context);
	}
	
	public DrawSurface(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}
	
	public DrawSurface(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	public void init(Context context)
	{
        // register our interest in hearing about changes to our surface
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        // make sure we get key events
        setFocusable(true); 
        // in case your application needs one or more timers,
        // you have to put them here
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				// do something
			}
		}, 10, 10);
	}
	
	@Override
    public boolean onTouchEvent(MotionEvent event)
    {
		// react on touch events		
		return true; 
    }
	
	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		// TODO Auto-generated method stub
	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) 
	{
		// as the constructor is not being called if
		// we resume from a previous state, we need
		// to create the drawing thread here.
        if(drawThread==null)
        {
	        drawThread = new DrawThread(getHolder(), getContext(), new Handler() {
	            @Override
	            public void handleMessage(Message m) {
	            }
	        });
	        // call the setter for the pointer to the model
	        drawThread.setDataModel(dataModel);
        }
        // start if not yet or still alive
		if(!drawThread.isAlive())
			drawThread.start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder arg0) 
	{
		drawThread.setRunning(false);
		// stop the drawThread properly
        boolean retry = true;
        while (retry) 
        {
            try 
            {
            	// wait for it to finish
            	drawThread.join();
                retry = false;
            } 
            catch (InterruptedException e) 
            {
            	// ignore any error
            }
        }
        // set it to null, so that a new one can be created in case of a resume
        drawThread=null;
	}
}

We next need to create the thread that actually does the painting. I named it DrawThread.

package lu.fisch.template;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.view.SurfaceHolder;

public class DrawThread extends Thread {

	/** Handle to the surface manager object we interact with */
    private SurfaceHolder mSurfaceHolder;
    /** Handle to the application context, used to e.g. fetch Drawables. */
    private Context mContext;
    /** Message handler used by thread to interact with TextView */
    private Handler mHandler;
    
    // indicates weather we are running or not
    private boolean running = false;
    
    private Object dataModel = new Object();

    public DrawThread(SurfaceHolder surfaceHolder, 
			  Context context,
			  Handler handler) 
    {
		// get handles to some important objects
		mSurfaceHolder = surfaceHolder;
		mHandler = handler;
		mContext = context;
	}
    
    public void setDataModel(Object dataModel)
    {
    	this.dataModel=dataModel;
    }
    
	private void draw(Canvas c) 
	{
		if(running)
		{
	        // do your paintings here ...
			// clean background
			Paint paint = new Paint();
			paint.setColor(Color.BLACK);
			c.drawRect(0, 0, c.getWidth(), c.getHeight(), paint);
			// draw some random lines
			paint = new Paint();
			paint.setColor(Color.WHITE);
			for(int i=0;i<10;i++)
			{
				c.drawLine((float) (Math.random()*c.getWidth()),(float) (Math.random()*c.getHeight()), 
						   (float) (Math.random()*c.getWidth()),(float) (Math.random()*c.getHeight()), paint);
			}
		}
	}
	
    @Override
    public void run() 
    {
    	while(running)
    	{
	        Canvas c = null;
	        try 
	        {
	        	// get the surface
	            c = mSurfaceHolder.lockCanvas(null);
	            synchronized (mSurfaceHolder) 
	            {
	            	if(c!=null)
	            	{
		            	draw(c);
	            	}
	            }
	        } 
	        finally 
	        {
	            // do this in a finally so that if an exception is thrown
	            // during the above, we don't leave the surface in an
	            // inconsistent state
	            if (c != null) 
	            {
	                mSurfaceHolder.unlockCanvasAndPost(c);
	            }
	        }
    	}
    }
	
    @Override
    public void start()
    {
    	super.start();
    	setRunning(true);
    }
    
    public boolean isRunning() {
		return running;
	}

	public void setRunning(boolean running) {
		this.running = running;
	}
}

In order to add it to your activity, you have to add these lines of code to you XML file:

    <lu.fisch.template.DrawSurface
        android:id="@+id/drawpanel"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:paddingLeft="@dimen/None"
        android:paddingTop="@dimen/None" />