Sunday, May 23, 2010

Android SurfaceView

It's a SurfaceView variation from the last exercise "Custom View with User Interaction".

Android SurfaceView

- Implement a new class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback.

- Implement the surfaceCreated(), surfaceDestroyed(), surfaceChanged() methods for SurfaceHolder.Callback.

- Implement a Thread for our SurfaceView.

- In SurfaceView's constructor, add the SurfaceView to SurfaceHolder for a callback, and create the Thread.
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);

- Modify the run() method of the Thread

package com.exercise.AndroidSurfaceViewUI;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class AndroidSurfaceViewUI extends Activity {

private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

private float initX, initY, radius;
private boolean drawing = false;

public class MySurfaceThread extends Thread {

private SurfaceHolder myThreadSurfaceHolder;
private MySurfaceView myThreadSurfaceView;
private boolean myThreadRun = false;

public MySurfaceThread(SurfaceHolder surfaceHolder, MySurfaceView surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}

public void setRunning(boolean b) {
myThreadRun = b;
}

@Override
public void run() {
// TODO Auto-generated method stub
//super.run();
while (myThreadRun) {
Canvas c = null;
try {
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder) {
myThreadSurfaceView.onDraw(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) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{

private MySurfaceThread thread;

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
//super.onDraw(canvas);
if(drawing){
canvas.drawCircle(initX, initY, radius, paint);
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//return super.onTouchEvent(event);
int action = event.getAction();
if (action==MotionEvent.ACTION_MOVE){
float x = event.getX();
float y = event.getY();
radius = (float) Math.sqrt(Math.pow(x-initX, 2) + Math.pow(y-initY, 2));
}
else if (action==MotionEvent.ACTION_DOWN){
initX = event.getX();
initY = event.getY();
radius = 1;
drawing = true;
}
else if (action==MotionEvent.ACTION_UP){
drawing = false;
}

return true;
}

public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}

private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);

setFocusable(true); // make sure we get key events

paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
}

@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);

MySurfaceView mySurfaceView = new MySurfaceView(this);
setContentView(mySurfaceView);
}
}


(In the View version in "Custom View with User Interaction", the view is forced to re-draw by invalidate() method, so the screen will be cleared. In this SurfaceView version, the onDraw() method is called inside thread's Run() method, so the drawing on the original canvas will not be cleared.)

Download the file.


next: Android SurfaceView, run in Thread with sleep()







It's a bug here!


Pls. refer to the article
"IllegalThreadStateException in LunarLander"
for details.


I'm Sorry about that! ()



No comments: