|
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" /> |