|
Threaded drawings :: On request The here explained approach repaints the drawing surface on request. The here given repaint() method can also be called from within another thread. This is because the creation of the drawing thread is being delegatedt to the UI thread. The given example surface is repainted each time you touch the screen an each 10 seconds. 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 repaint(); } }, 10000, 10000); } @Override public boolean onTouchEvent(MotionEvent event) { // react on touch events repaint(); 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) { // do a first painting repaint(); } public void repaint() { // post a task to the UI thread this.post(new Runnable() { @Override public void run() { // create a new drawThread 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 the thread drawThread.start(); } }); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // 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() { 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); } running=false; } } @Override public void start() { running=true; super.start(); } public boolean isRunning() { return 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" /> |