The following code shows how to Draw to SurfaceView with thread.
Code revised from
Android Recipes:A Problem-Solution Approach
http://www.apress.com/9781430234135
ISBN13: 978-1-4302-3413-5
Main layout xml file
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button_erase" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Erase" /> <SurfaceView android:id="@+id/surface" android:layout_width="300dp" android:layout_height="300dp" android:layout_gravity="center" /> </FrameLayout>
Main Activity Java code
import java.util.ArrayList; //from w ww . ja v a 2 s . com import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; public class MainActivity extends Activity implements View.OnClickListener, View.OnTouchListener, SurfaceHolder.Callback { private SurfaceView mSurface; private DrawingThread mThread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //Attach listener to button findViewById(R.id.button_erase).setOnClickListener(this); //Set up the surface with a touch listener and callback mSurface = (SurfaceView) findViewById(R.id.surface); mSurface.setOnTouchListener(this); mSurface.getHolder().addCallback(this); } @Override public void onClick(View v) { mThread.clearItems(); } public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { mThread.addItem((int) event.getX(), (int) event.getY()); } return true; } @Override public void surfaceCreated(SurfaceHolder holder) { mThread = new DrawingThread(holder, BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); mThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mThread.updateSize(width, height); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mThread.quit(); mThread = null; } private static class DrawingThread extends HandlerThread implements Handler.Callback { private static final int MSG_ADD = 100; private static final int MSG_MOVE = 101; private static final int MSG_CLEAR = 102; private int mDrawingWidth, mDrawingHeight; private SurfaceHolder mDrawingSurface; private Paint mPaint; private Handler mReceiver; private Bitmap mIcon; private ArrayList<DrawingItem> mLocations; private class DrawingItem { //Current location marker int x, y; //Direction markers for motion boolean horizontal, vertical; public DrawingItem(int x, int y, boolean horizontal, boolean vertical) { this.x = x; this.y = y; this.horizontal = horizontal; this.vertical = vertical; } } public DrawingThread(SurfaceHolder holder, Bitmap icon) { super("DrawingThread"); mDrawingSurface = holder; mLocations = new ArrayList<DrawingItem>(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mIcon = icon; } @Override protected void onLooperPrepared() { mReceiver = new Handler(getLooper(), this); //Start the rendering mReceiver.sendEmptyMessage(MSG_MOVE); } @Override public boolean quit() { // Clear all messages before dying mReceiver.removeCallbacksAndMessages(null); return super.quit(); } @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_ADD: //Create a new item at the touch location, with a randomized start direction DrawingItem newItem = new DrawingItem(msg.arg1, msg.arg2, Math.round(Math.random()) == 0, Math.round(Math.random()) == 0); mLocations.add(newItem); break; case MSG_CLEAR: //Remove all objects mLocations.clear(); break; case MSG_MOVE: //Render a frame Canvas c = mDrawingSurface.lockCanvas(); if (c == null) { break; } //Clear canvas first c.drawColor(Color.BLACK); //Draw each item for (DrawingItem item : mLocations) { //Update location item.x += (item.horizontal ? 5 : -5); if (item.x >= (mDrawingWidth - mIcon.getWidth()) ) item.horizontal = false; if (item.x <= 0) item.horizontal = true; item.y += (item.vertical ? 5 : -5); if (item.y >= (mDrawingHeight - mIcon.getHeight()) ) item.vertical = false; if (item.y <= 0) item.vertical = true; c.drawBitmap(mIcon, item.x, item.y, mPaint); } mDrawingSurface.unlockCanvasAndPost(c); break; } //Post the next frame mReceiver.sendEmptyMessage(MSG_MOVE); return true; } public void updateSize(int width, int height) { mDrawingWidth = width; mDrawingHeight = height; } public void addItem(int x, int y) { //Pass the location into the Handler using Message arguments Message msg = Message.obtain(mReceiver, MSG_ADD, x, y); mReceiver.sendMessage(msg); } public void clearItems() { mReceiver.sendEmptyMessage(MSG_CLEAR); } } }