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
Related
I Writing a very simple game in android , the game is like touching a shapes (like rectangle,circle,arc...) and for doing this i write a Thread MainGameTread.class:
package com.example.komeil.surfaceview_2;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.SurfaceHolder;
import java.util.Random;
/**
* Created by Komeil on 04/11/2016.
*/
public class MainGameThread extends Thread {
private boolean running;
private SurfaceHolder surfaceHolder;
private MainGameView mainGameView;
private String shapeType;
private Random rnd;
private int xPos;
private int yPos;
private int radius;
private int left;
private int right;
private int top;
private int bottom;
private int color;
public MainGameThread (SurfaceHolder surfaceHolder,MainGameView mainGameView)
{
super();
this.surfaceHolder = surfaceHolder;
this.mainGameView = mainGameView;
}
public void setRunning(boolean running)
{
this.running = running;
}
#Override
public void run() {
while (running)
{
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder)
{
makeChoose();
mainGameView.onDraw(canvas);
}
}
finally {
if(canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
private void makeChoose()
{
int radius;
rnd = new Random();
switch (rnd.nextInt(2))
{
case 0:
setShapeType("Rectangle");
setColor(Color.rgb(rnd.nextInt(255),rnd.nextInt(255),rnd.nextInt(255)));
setXpos(rnd.nextInt(mainGameView.getWidth()));
setYpos(rnd.nextInt(mainGameView.getHeight()));
setTop(rnd.nextInt(mainGameView.getHeight()));
setBottom(rnd.nextInt(mainGameView.getHeight()));
setLeft(rnd.nextInt(mainGameView.getWidth()));
setRight(rnd.nextInt(mainGameView.getWidth()));
break;
case 1:
setShapeType("Circle");
setColor(Color.rgb(rnd.nextInt(255),rnd.nextInt(255),rnd.nextInt(255)));
setXpos(rnd.nextInt(mainGameView.getWidth()));
setYpos(rnd.nextInt(mainGameView.getHeight()));
radius = rnd.nextInt(mainGameView.getWidth()-getXpos());
setRadius(radius);
break;
// case 2:
// setShapeType("Arc");
// setXpos(rnd.nextInt(mainGameView.getWidth()));
// setYpos(rnd.nextInt(mainGameView.getHeight()));
// break;
}
}
private void setShapeType(String shapeType)
{
this.shapeType = shapeType;
}
private void setColor(int color) {
this.color = color;
}
public int getColor() {
return color;
}
private void setRadius(int radius)
{
this.radius = radius;
}
public int getRadius()
{
return radius;
}
public int getBottom() {
return bottom;
}
public int getLeft() {
return left;
}
public int getRight() {
return right;
}
public int getTop() {
return top;
}
private void setBottom(int bottom) {
this.bottom = bottom;
}
private void setLeft(int left) {
this.left = left;
}
private void setRight(int right) {
this.right = right;
}
private void setTop(int top) {
this.top = top;
}
private void setXpos(int xPos)
{
this.xPos = xPos;
}
public int getXpos()
{
return xPos;
}
private void setYpos(int yPos)
{
this.yPos = yPos;
}
public int getYpos()
{
return yPos;
}
public String getShapeType()
{
return shapeType;
}
}
so when i use for drawing in UI Thread it's work. but when i touching rectangle
it's like nothing happend(i use score and i want update score when rectangle touched) but score not shown in screen and some times show itself and Disappeared very fast.
This below code for my MainGameView.class:
package com.example.komeil.surfaceview_2;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Created by Komeil on 04/11/2016.
*/
public class MainGameView extends SurfaceView implements SurfaceHolder.Callback {
private Bitmap bmp;
MainGameThread mainGameThread;
private int x;
private Paint paint;
private Paint textWhite;
private int score;
private Rect rect;
private boolean touched;
public MainGameView(Context context) {
super(context);
getHolder().addCallback(this);
mainGameThread = new MainGameThread(getHolder(),this);
setFocusable(true);
paint = new Paint();
textWhite = new Paint();
textWhite.setAntiAlias(true);
textWhite.setColor(Color.WHITE);
textWhite.setTextSize(30);
paint.setAntiAlias(true);
bmp = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mainGameThread.setRunning(true);
mainGameThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mainGameThread.setRunning(false);
while (retry)
{
try {
mainGameThread.join();
retry = false;
}
catch (InterruptedException ex)
{
}
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.GRAY);
if(x<getWidth()-bmp.getWidth())
x+=2;
else
x=0;
canvas.drawBitmap(bmp,x,10,null);
switch (mainGameThread.getShapeType())
{
case "Rectangle":
paint.setColor(mainGameThread.getColor());
canvas.drawRect(mainGameThread.getLeft(),mainGameThread.getTop(),mainGameThread.getRight(),mainGameThread.getBottom(),paint);
break;
case "Circle":
paint.setColor(mainGameThread.getColor());
canvas.drawCircle(mainGameThread.getXpos(),mainGameThread.getYpos(),mainGameThread.getRadius(),paint);
break;
// case "Arc":
// paint.setColor(mainGameThread.getColor());
// canvas.drawArc(mainGameThread.getLeft(),mainGameThread.getRight()
// ,mainGameThread.getTop(),mainGameThread.getBottom(),);
// break;
}
if(touched)
{
canvas.drawText(String.valueOf(score),getWidth()/2,50,textWhite);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int eventAction = event.getAction();
int xEvent = (int)event.getX();
int yEvent = (int)event.getY();
switch (eventAction)
{
case MotionEvent.ACTION_DOWN:
switch (mainGameThread.getShapeType())
{
case "Rectangle":
rect = new Rect(mainGameThread.getLeft(),mainGameThread.getTop(),mainGameThread.getRight(),mainGameThread.getBottom());
if(rect.contains(xEvent,yEvent))
{
touched = true;
score +=1;
}
else
{
touched = false;
}
break;
case "Circle":
break;
case "Arc":
break;
}
break;
case MotionEvent.ACTION_UP:
touched = false;
break;
}
return super.onTouchEvent(event);
}
}
So How i can show score and do i need another thread for score?
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.
I'm trying to create moving text.I have crated surface view and thread for looping it.but it not show me a moving motion but draw that text each after like * ** * * in infinite.
But what I need was move that this point to that** -> ** got it?
this is my code
package com.CurvePackage.Curve;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
public class Origin extends SurfaceView implements SurfaceHolder.Callback {
Context context1;
private MainThread thread;
private int x=0;
private int y=0;
public Origin(Context context) {
super(context);
// TODO Auto-generated constructor stub
setWillNotDraw(false);
context1 = context;
getHolder().addCallback(this);
thread = new MainThread(getHolder(), this);
setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
paint.setTextSize(23);
paint.setFakeBoldText(true);
paint.setColor(Color.YELLOW);
// int score=(10-sprites.size()*100);
x=x+20;
y=y+20;
canvas.drawText("ewqewqe", x, y, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return super.onTouchEvent(event);
// Toast.makeText(getba, "Replay clicked!", Toast.LENGTH_SHORT).show();
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
thread.setRunning(false);
// TODO Auto-generated method stub
// boolean retry = true;
// while (retry) {
// try {
// thread.join();
// retry = false;
// } catch (InterruptedException e) {
// // try again shutting down the thread
// }
// }
}
}
Main Thread
package com.CurvePackage.Curve;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
// flag to hold game state
private boolean running;
private SurfaceHolder surfaceHolder;
private Origin origin;
static final long FPS = 15;
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = origin.getHolder().lockCanvas();
synchronized (origin.getHolder()) {
origin.onDraw(c);
}
} finally {
if (c != null) {
origin.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
public MainThread(SurfaceHolder surfaceHolder, Origin origin) {
super();
this.surfaceHolder = surfaceHolder;
this.origin = origin;
}
}
You need to paint the entire background in your onDraw method, before you paint your text.
Paint p2 = new Paint();
p2.setStyle(Style.FILL);
canvas.drawRect(0, 0, screenWidth, screenHeight, p2);
//draw text here
This will completely paint over the text from the previous time the canvas was drawn, and will remove this dragging effect.
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)