Tuesday, May 25, 2010

Android SurfaceView, run in Thread with sleep()

Further works on the last exercise "Android SurfaceView", a call to sleep(500) is introduced in run() of the thread, such that the onDraw() will be called in half second.

In this exercise, there is a point on the screen. When user touch on screen, the point will run from the current position to the touched position, in speed of half the distance per second.

Android SurfaceView, run in Thread with sleep()

AndroidSurfaceViewUI.java
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;
private float targetX, targetY;
private boolean drawing = true;

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);
}

sleep(500);

} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} 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.drawRGB(0, 0, 0);
canvas.drawCircle(initX, initY, 3, paint);
if ((initX==targetX) && (initY==targetY)){
drawing = false;
}
else{
initX = (initX + targetX)/2;
initY = (initY + targetY)/2;
}
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//return super.onTouchEvent(event);
int action = event.getAction();

if (action==MotionEvent.ACTION_DOWN){
targetX = event.getX();
targetY = event.getY();
drawing = true;
}

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);

initX = targetX = 0;
initY = targetY = 0;

}

@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);
}
}



Download the file.

6 comments:

Unknown said...

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);

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


why can't I use R.layout.main???
It always occurs forcing close error...
But LunarLander can, I don't know how he did it

Unknown said...
This comment has been removed by the author.
Erik said...

To define surfaceView in main.xml, refer to another article:
http://android-er.blogspot.com/2010/05/another-exercise-of-surfaceview-in.html

Mike said...

This is a great example, exactly what I needed for helping me with my project. I created a similar application using your basic template, but it seems to run fairly slow in the emulator.

I was wondering if all of the redraws are maybe taxing on the resources? Do you know anything else that could be slowing the application down?

I am trying to use your example to create an interactive game with other objects moving around the screen and using the down and move for two different user inputs.

Erik said...

Hello Mike,

I don't know the exact details of your case. You can modify the parameter of sleep() to make it running faster.

Anonymous said...

Thanks a lot :)