I have a SurfaceView on wich am drawing a small circle periodically with a special thread
but i want to when i press the surfaceView the thread stops drawing the circle and when i repress it the thread resume drawing the circle again.
I tried with thread methods and i can stop temporarily it with its sleep() method but i did not understand how to use wait and notify and i even found some exemples but did not get help from them
My code is :
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private float x = 100;
private float y = 100;
private int radius = 20;
private Paint paint;
private SurfaceHolder mSurfaceHolder;
private DrawingThread mTh ead;
private Context myContext;
public GameView(Context context) {
super(context);
this.myContext = context;
setWillNotDraw(false);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setTextAlign(Paint.Align.LEFT);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
}
public void onDraw(Canvas canvas){
canvas.drawCircle(x, y, radius, paint);
}
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
int X = (int)event.getX();
int Y = (int)event.getY();
switch (eventaction ) {
case MotionEvent.ACTION_DOWN:
// I want to do my job here
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mThread = new DrawingThread(mSurfaceHolder, myContext);
mThread.mRun = true;
mThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public final class DrawingThread extends Thread {
public boolean att = true;
public long delaiAttente = 1000;
boolean mRun;
Canvas mcanvas;
SurfaceHolder surfaceHolder;
Context context;
public DrawingThread(SurfaceHolder sholder, Context ctx)
{
surfaceHolder = sholder;
context = ctx;
mRun = false;
}
void setRunning(boolean bRun)
{
mRun = bRun;
}
boolean keepDrawing = true;
#Override
public void run() {
while (keepDrawing) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
draw(canvas);
}
}
catch(Exception e){
}
finally {
if (canvas != null)
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
waitThreaed();
}
}
public void waitThreaed() {
try {
x = (float) (getWidth()*Math.random());
y = (float) (getHeight()*Math.random());
this.sleep(1000);
postInvalidate();
} catch (InterruptedException e) {
}
}
}
}
Can't you just use something like this:
Timer drawTimer = new Timer("draw");
updateTimer.schedule(new TimerTask() {
public void run() {
draw();
}
}, 0, 1000);
private void draw() {
runOnUiThread(new Runnable() {
public void run() { ...}}}
I don't see why you need to subclass Thread.
Related
This message is being displayed when i try to generate a signed apk
Error in surfaceView implements Runnable class should provide a default constructor (a public constructor with no arguments)"
and yet surfaceView implements Runnable does not support a default constructor... when I I try to put a default constructor an error comes again
the class doesn't allow a default constructor
what else could be done to solve this problem?
Here is my code
public class view extends SurfaceView implements
Runnable {
volatile boolean playing;
private Thread gameThread = null;
private king myKing;
private Paint paint;
private Canvas canvas;
private SurfaceHolder surfaceHolder;
private lebel myLebel;
private fire myFire;
private worldking peace;
int screenX;
int countCollisions;
boolean flag ;
int i;
private boolean isGameOver ;
private boolean congrats;
int score;
int highScore[] = new int[4];
SharedPreferences sharedPreferences;
public view(Context context, int screenX, int screenY) {
super(context);
myKing = new king(context, screenX, screenY);
surfaceHolder = getHolder();
paint = new Paint();
myLebel = new lebel(context, screenX, screenY);
myFire = new fire(context);
peace = new worldking(context, screenX, screenY);
this.screenX = screenX;
countCollisions = 0;
isGameOver = false;
congrats= false;
score = 0;
}
#Override
public void run() {
while (playing) {
update();
draw();
control();
}
}
private void update() {
score++;
myKing.update();
myFire.setX(-250);
myFire.setY(-250);
if (myLebel.getX() == screenX) {
flag = true;
}
myLebel.update(myKing.getSpeed());
if (Rect.intersects(myKing.getDetectCollision(),
myLebel.getDetectCollision())) {
myFire.setX(myLebel.getX());
myFire.setY(myLebel.getY());
myLebel.setX(-200);
}
peace.update(myKing.getSpeed());
if (Rect.intersects(myKing.getDetectCollision(),
peace.getDetectCollision())) {
myFire.setX(peace.getX());
myFire.setY(peace.getY());
playing = false;
isGameOver = true;
myLebel.setX(-200);
}
}
private void draw() {
if (surfaceHolder.getSurface().isValid()) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.BLACK);
paint.setTextSize(30);
paint.setColor(WHITE);
canvas.drawText("SCORE:"+score,100,50,paint);
canvas.drawBitmap(
myKing.getBitmap(),
myKing.getX(),
myKing.getY(),
paint);
canvas.drawBitmap(
myLebel.getBitmap(),
myLebel.getX(),
myLebel.getY(),
paint
);
canvas.drawBitmap(
myFire.getBitmap(),
myFire.getX(),
myFire.getY(),
paint
);
canvas.drawBitmap(
peace.getBitmap(),
peace.getX(),
peace.getY(),
paint
);
if(isGameOver){
paint.setTextSize(100);
paint.setColor(WHITE);
paint.setTextAlign(Paint.Align.CENTER);
int yPos=(int) ((canvas.getHeight() / 2) -
((paint.descent() + paint.ascent()) / 2));
canvas.drawText("Oops! Try
Again !",canvas.getWidth()/2,yPos,paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
private void control() {
try {
gameThread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void pause() {
playing = false;
try {
gameThread.join();
} catch (InterruptedException e) {
}
}
public void resume() {
playing = true;
gameThread = new Thread(this);
gameThread.start();
}
I am beginner to multithreading in Java and in my Android application, i have that SurfaceView on wich am drawing a circle randomlly but i want to be able to pause that drawing by pressing the screen (ACTION_DOWN) and resume it the next time i press it again :
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView /**/implements SurfaceHolder.Callback {
private float x = 100;
private float y = 100;
private int radius = 20;
private Paint paint;
private SurfaceHolder mSurfaceHolder;
private DrawingThread mThread;
private Context myContext;
public GameView(Context context) {
super(context);
this.myContext = context;
setWillNotDraw(false);
paint = new Paint();
/**/
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setTextAlign(Paint.Align.LEFT);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
//paint.setTextSize(15);
}
public void onDraw(Canvas canvas){
canvas.drawCircle(x, y, radius, paint);
}
/**/
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mThread = new DrawingThread(mSurfaceHolder, myContext);
mThread.mRun = true;
mThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
public synchronized boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
int X = (int)event.getX();
int Y = (int)event.getY();
switch (eventaction ) {
case MotionEvent.ACTION_DOWN:
this.mThread.canPause = !this.mThread.canPause;
synchronized(this.mSurfaceHolder){
if(this.mThread.canPause){
this.mSurfaceHolder.notify();
}
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
public final class DrawingThread extends Thread {
public boolean canPause = false;
boolean mRun;
Canvas mcanvas;
SurfaceHolder surfaceHolder;
Context context;
public DrawingThread(SurfaceHolder sholder, Context ctx)
{
surfaceHolder = sholder;
context = ctx;
mRun = false;
}
void setRunning(boolean bRun)
{
mRun = bRun;
}
boolean keepDrawing = true;
#Override
public void run() {
while (keepDrawing) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
while(canPause){
try {
mSurfaceHolder.wait();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
waitThreaed();
draw(canvas);
}
}
catch(Exception e){
}
finally {
if (canvas != null)
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
public void waitThreaed() {
try {
x = (float) (getWidth()*Math.random());
y = (float) (getHeight()*Math.random());
this.sleep(1000);
postInvalidate();
} catch (InterruptedException e) {
}
}
}
}
In fact with that code the drawing can be paused but can not be resumed
In order to call wait() you must have synchronized on the object you are waiting on.
See this question for a discussion of that: Why must wait() always be in synchronized block
I am creating a paint app but i am not able to draw /paint anything over an image please help me out :
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
private Boolean _run;
protected DrawThread thread;
private Bitmap mBitmap;
public boolean isDrawing = true;
public DrawingPath previewPath;
private CommandManager commandManager;
public DrawingSurface(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
commandManager = new CommandManager();
thread = new DrawThread(getHolder());
}
private Handler previewDoneHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
isDrawing = false;
}
};
class DrawThread extends Thread{
private SurfaceHolder mSurfaceHolder;
public DrawThread(SurfaceHolder surfaceHolder){
mSurfaceHolder = surfaceHolder;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas canvas = null;
while (_run){
if(isDrawing == true){
try{
canvas = mSurfaceHolder.lockCanvas(null);
if(mBitmap == null){
// mBitmap = Bitmap.createBitmap (1, 1, Bitmap.Config.ARGB_8888);
mBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.splashscreen);
}
// final Canvas c = new Canvas (mBitmap);
mBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.splashscreen);
// c.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
// commandManager.executeAll(c,previewDoneHandler);
// previewPath.draw(c);
canvas.drawBitmap (mBitmap, 0, 0,null);
} finally {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
public void addDrawingPath (DrawingPath drawingPath){
commandManager.addCommand(drawingPath);
}
// Bitmap mBitmap = Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter);
public boolean hasMoreRedo(){
return commandManager.hasMoreRedo();
}
public void redo(){
isDrawing = true;
commandManager.redo();
}
public void undo(){
isDrawing = true;
commandManager.undo();
}
public boolean hasMoreUndo(){
return commandManager.hasMoreUndo();
}
public Bitmap getBitmap(){
return mBitmap;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
mBitmap = Bitmap.createBitmap (width, height, Bitmap.Config.ARGB_8888);;
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
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) {
// we will try it again and again...
}
}
}
}
Why not make it easier on yourself and split your application across multiple surfaceviews. Use framelayout so that you can control the order of the views. I assume you want to be able to handle touch events (its a paint program right?) so handle those in one view and your drawing in another that way the code will be more manageable. Create two custom surfaceviews (In my case one was a GLSurfaceView, and the other was a SurfaceView). One view implements the image and the second can handle a GUI with graphics and or buttons. The key is creating a custom GLSurfaceView (or in your case two Surfaceviews) in XML that uses the class names of the extended SurfaceViews. Also you must make the GUI view transparent. So your Surface view that calls your drawing class and handles touch events would have code like this:
public class MainSurfaceView extends GLSurfaceView
//Constructor
public MainSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, "Constructor called...");
this.context = context;
mRenderer = new MainRenderer();
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
setRenderer(mRenderer);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
setZOrderOnTop(true);
//Render only when there is a change
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
//TouchEvent handler
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "onTouchEvent called...");
x = event.getX();
y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
//Reverse direction of rotation if above midline
if (y > getHeight() / 2) {
dx = dx * -1;
}
//Reverse direction of rotation if of the midline
if (y < getWidth() / 2) {
dy = dy * -1;
}
Main.mAngle += (dx + dy) * TOUCH_SCALE_FACTOR;
TextView txtView = (TextView) ((Activity)context).findViewById(R.id.mangle);
txtView.setText("Angle: " + String.valueOf(Main.mAngle));
requestRender();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
Put you image to be drawn on a separate surface view (it will also make it easier to change the image). So you Activity class would have code like this (note my second view is a GLsurfaceview):
public class Main extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate called...");
Log.d(TAG, "state is: " + state.toString());
super.onCreate(savedInstanceState);
// When working with the camera, it's useful to stick to one orientation.
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
//Set full screen
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
//Substantiate surfaces
cameraView = (CameraView) findViewById(R.id.camera);
mGLView = (MainSurfaceView) findViewById(R.id.glSurfaceView);
//Initialize TextViews
txtView = (TextView) findViewById(R.id.mangle);
txtView.setText("Angle: " + String.valueOf(mAngle));
}
}
Hope that helps a little...
i want to rotate an image(png) in android depending upon the intensity of touch.
Any Idea?
public class GetmouseActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
private Bitmap mBitmap;
private ViewThread mThread;
private int mX;
private int mY;
public Panel(Context context) {
super(context);
mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.icon);
getHolder().addCallback(this);
mThread = new ViewThread(this);
}
public void doDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
Paint paint = new Paint();
paint.setStrokeWidth(25);
for (int y = 30, alpha = 255; alpha > 2; alpha >>= 1, y += 10) {
paint.setAlpha(alpha);
canvas.drawLine(0, y, 100, y, paint);
}
canvas.drawBitmap(mBitmap, mX, mY, null);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread.isAlive()) {
mThread.setRunning(false);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mX = (int) event.getX() - mBitmap.getWidth() / 2;
mY = (int) event.getY() - mBitmap.getHeight() / 2;
return super.onTouchEvent(event);
}
}
public class ViewThread extends Thread {
private Panel mPanel;
private SurfaceHolder mHolder;
private boolean mRun = false;
public ViewThread(Panel panel) {
mPanel = panel;
mHolder = mPanel.getHolder();
}
public void setRunning(boolean run) {
mRun = run;
}
#Override
public void run() {
Canvas canvas = null;
while (mRun) {
canvas = mHolder.lockCanvas();
if (canvas != null) {
mPanel.doDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
try this
I am trying to draw on a surface view, but I get a black screen. My xml layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<com.example.surfaceview.MySurface android:id="#+id/padview"
android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>
Important parts of my code: MySurface.java
public class MySurface extends SurfaceView implements SurfaceHolder.Callback {
public DrawingThread thread;
public MySurface(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder surfaceholder = getHolder();
surfaceholder.addCallback(this);
thread = new DrawingThread(surfaceholder, context, new Handler() {
#Override
public void handleMessage(Message m) {
// Do some handle thing
}
});
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder tholder, int format, int width, int height) {
thread.setSurfaceSize(width, height);
thread.holder = tholder;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.running = true;
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.running = false;
while(retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public Thread getThread() {
return thread;
}
public class DrawingThread extends Thread {
private SurfaceHolder holder;
private Context context;
private Handler handle;
private Paint background;
private Rect blank;
public boolean running;
public boolean created;
public int canvasheight;
public int canvaswidth;
public PadThread(SurfaceHolder tholder, Context tcontext, Handler thandler) {
holder = tholder;
context = tcontext;
handle = thandler;
// Temporary canvas dimentions
canvaswidth = 1;
canvasheight = 1;
running = false;
created = false;
background = new Paint();
background.setColor(R.color.white);
blank = new Rect(0, 0, canvaswidth, canvasheight);
}
#Override
public void run() {
Log.d("SurfaceView Test", "Drawing thread run");
while(running) {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
synchronized(holder) {
// update object states
// get user input gestures
drawing(canvas);
}
} finally {
if(canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
}
private void drawing(Canvas canvas) {
// Clear screen
canvas.drawRect(blank, background);
// Draw Things
}
public void setSurfaceSize(int width, int height) {
synchronized(holder) {
canvaswidth = width;
canvasheight = height;
// New background rect
blank.set(0, 0, canvaswidth, canvasheight);
}
}
}
}
The code is based off of Google's Lunar Landar SurfaceView example at http://developer.android.com/resources/samples/LunarLander/index.html
I know that all of the code is being reached through logging.
change drawing function
background.setColor(Color.RED);
canvas.drawRect(new Rect(10, 10, 100, 100), background);
(There are test values for colors and rect)