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