How to set timer in View class? - android

I am trying to set a text which acts as a timer. I'll create timer easily if i extend Activity class. But i am facing lot of problem in this View class. Here i made a code where radius of circle will be reducing and it will be increased for each touch on screen. Simultaneously i need a timer running on the top. Because i need to increase the reducing speed after every 10 seconds.
So here timer plays an important role. I tried using thread , which should update the text for every 1 second . But it is showing this exception IllegalThreadStateException.
Is there any other way to implement timer in this screen ?
Or What mistake i did in my code..
Thanks for you help friends..
package com.kbt.testcircle;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class MyView extends View {
int radius = 100,i=0;
boolean freeTouched = false;
Path freePath;
Handler handler = new Handler();
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void calThread() {
/*
* Thread th=new Thread(){ public void run(){ try { sleep(2000); } catch
* (InterruptedException e) { // TODO Auto-generated catch block
* e.printStackTrace(); } finally{ radius-=1;
* Log.i("kbt","inside thread 800 seconds"); } } }; th.start();
*/
handler.postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
radius -= 1;
Log.i("kbt", "inside thread 800 seconds");
invalidate();
}
}, 500);
Log.i("kbt", "Inside thread");
}
Thread th=new Thread()
{
public void run(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
i++;
}
},1000);
}
};
#Override
protected void onDraw(Canvas canvas) throws IllegalThreadStateException
{
// TODO Auto-generated method stub
th.start();
Log.i("kbt","starting");
super.onDraw(canvas);// th.start();
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(3);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(0);
paint.setTextSize(25);
canvas.drawText("Timer : "+i, getWidth()/4, getHeight()/4, paint);
calThread();
Log.i("kbt", "Inside clled");
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_DOWN:
radius+=5;
invalidate();
/* freeTouched = true;
freePath = new Path();
freePath.moveTo(event.getX(), event.getY()); */
break;
case MotionEvent.ACTION_MOVE:
/* freePath.lineTo(event.getX(), event.getY());
invalidate(); */
break;
}
return true;
}
}

But it is showing this exception IllegalThreadStateException.
It caused by non-runnable or non-threading class. A class that extends View has no background thread on it, so that you get IllegalThreadStateException.
Is there any other way to implement timer in this screen?
Java provided a Timer class to be used for all of class types:
Timer timer = new Timer();
TimerTask task = new TimerTask(){
#Override
public void run() {
// do your thing here
}
};
timer.schedule(task,
1, // delay the task 1ms before executed
10000); // repeating your task every 10000ms, i.e. 10 seconds

If you really one to use a thread, you could only start the thread once. If you want to start thread for many times, use Runnable instead.

Related

How Can I increase the radius of the circle after each a second

How Can I increase the radius of the circle after each a second? I searched about this issue in stackoverflow and I added the Thread.sleep(1000); to my code as follows:
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
for(int r=1;r<=70;r++)
try {
canvas.drawCircle(getWidth() / 2, getHeight() / 2, r, paint);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But I think that it is wrong to do this. Because when I run in my device it can not work well.
Please find custom view class to update view frequently..
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class CustomView extends View {
Paint paint;
int radius = 0;
public CustomView(Context context) {
super(context);
init();
}
private void init() {
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setStrokeWidth(5f);
}
public void updateView(int radius) {
this.radius = radius;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
}
}
And call this method whenever you want to start animation :
public void startViewAnimation() {
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (i < 70) { // Please change '70' according to how long you want to go
runOnUiThread(new Runnable() {
#Override
public void run() {
int baseRadius=20; // base radius is basic radius of circle from which to start animation
customView.updateView(i+baseRadius);
i++;
}
});
} else {
i = 0;
}
}
}, 0, 500); // change '500' to milliseconds for how frequent you want to update radius
}
And Here how to call it :
RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.rootView);
customView = new CustomView(this);
relativeLayout.addView(customView);
startViewAnimation();
And here is defined variables :
private int i = 1;
CustomView customView;
Thanks..!!
You could do it with a timer. It might not be exactly a second between them (since it does some magic to save power), but it will probably work for your intended purpose.
I don't think pausing and making multiple draw calls inside the onDraw method is a good idea. Since you are pausing the GUI thread it probably won't like it (it might even wake up if someone does something to it).
I think you can use it here and gives time and intervals as you wanted
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
//Perform background work here
handler.post(new Runnable() {
public void run() {
//Perform GUI updation work here
// increase radius with your method
}
});
}
};
timer.schedule(doAsynchronousTask, 1, 1000);
Check out this answer here
It shows the usage of Handler class wich creates such behaviour

Android Custom View with Handler

I am looking for an easy way to animate custom views in Android. I am trying to avoid using the animator object but want to work with raw threads. What I have done is created a custom view by creating a class that extends android.view.View. I then override the onDraw method and use the canvas to draw a rect. What I would like is the rect to shrink, so I keep a variable that represents the x value of the right hand side of the rectangle. I would then like the the rectangle's right edge shrink in over time. What I would have liked to do is create a new thread, start it and have it change the value of the rectangle. That all works except the view doesn't get updated until you call View.invalidate. The problem is that I can't call that from the thread that I spawned because it is not the UI thread. I read solutions on using Handlers... but I am still unsure if that is the correct solution and then how to use them.
package com.example.practicum;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
public class TimerControl extends View implements Runnable, Handler.Callback
{
private Paint paint;
private Rect rect;
private Thread t;
private Handler h;
public TimerControl(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
paint = new Paint();
paint.setColor(Color.BLUE);
rect = new Rect(0,0,60,60);
t = new Thread(this);
t.start();
h = new Handler(this);
//h.post(this);
}
#Override
public void onDraw(Canvas canvas)
{
canvas.drawRect(rect, paint);
}
#Override
public void run()
{
rect.right = rect.right-1;
while(true)
{
rect.right = rect.right-1;
this.invalidate();
try
{
Thread.sleep(5000);
h.sendEmptyMessage(0);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public boolean handleMessage(Message msg)
{
return false;
}
}
you can define a global Handler (in the UI thread):
Handler mHandler = new Handler();
then, from your thread, call:
mHandler.post(new Runnable() {
public void run() {
// call some method on the UI thread
}
});

Scroll Background Like Lunar Lander or Ninja Jump Game - Android

I'm developing a 2d Game using Canvas/Surfaceview and have a problem with scrolling my background image.
Check out the game - http://youtu.be/4Gi5rRqzZ3M
In the NinJump game, the character Ninja is just jumping in X coordinates and Background image is scrolling at a very high speed, making Ninja look like it is actually running.
I have created the basic setup, created the Ninja, added jump functionality, added background. Now I want to repeat the same background over and over again. How can I accomplish that?
Below are my source files - Main Activity Class
package com.abc.apps;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
public class LadderActivity extends Activity {
private static final String TAG = LadderActivity.class.getSimpleName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// requesting to turn the title OFF
requestWindowFeature(Window.FEATURE_NO_TITLE);
// making it full screen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// set our MainGamePanel as the View
setContentView(new MainGameBoard(this));
Log.d(TAG, "View added");
}
#Override
protected void onDestroy() {
Log.d(TAG, "Destroying...");
super.onDestroy();
}
#Override
protected void onStop() {
Log.d(TAG, "Stopping...");
super.onStop();
}
}
Game Board extends SurfaceView
package com.abc.apps;
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainGameBoard extends SurfaceView implements SurfaceHolder.Callback{
private MainGameLoop thread;
private Monkey monkey;
private static final String TAG = MainGameLoop.class.getSimpleName();
int currentX, currentY;
public MainGameBoard(Context context) {
super(context);
// TODO Auto-generated constructor stub
// adding the callback (this) to the surface holder to intercept events
//This line sets the current class (MainGamePanel) as the handler for the events happening on the actual surface
getHolder().addCallback(this);
// create monkey and load bitmap INITIALIZE AT LEFT
monkey = new Monkey(BitmapFactory.decodeResource(getResources(), R.drawable.actor),60, 340);
// create the game loop thread
thread = new MainGameLoop(getHolder(), this);
// make the GamePanel focusable so it can handle events.
setFocusable(true);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// 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) {
// TODO Auto-generated method stub
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//For jumping Left
if (event.getX() < (getWidth()/2 - 32)) {
// Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
//Log.d(TAG, "Jump Left");
// Sleep so that the main thread doesn't get flooded with UI events.
try {
Thread.sleep(32);
monkey.setX((getWidth()/2 - 60));
monkey.setY(monkey.getY()-70);
} catch (InterruptedException e) {
// No big deal if this sleep is interrupted.
}
}
//For Jumping Right
if (event.getX() > (getWidth()/2 + 32)) {
//Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
//Log.d(TAG, "Jump Right");
// Sleep so that the main thread doesn't get flooded with UI events.
try {
Thread.sleep(32);
monkey.setX((getWidth()/2 + 60));
monkey.setY(monkey.getY()-70);
} catch (InterruptedException e) {
// No big deal if this sleep is interrupted.
}
}
/* //Middle Portion
if (event.getX() > (getWidth()/2 - 32) && event.getX() < (getWidth()/2 +32)) {
//thread.setRunning(false);
//((Activity)getContext()).finish();
}*/
}
return true;
}
public void render(Canvas canvas) {
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, 0,null);
monkey.draw(canvas);
}
/* #Override
protected void onDraw(Canvas canvas){
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_scene), 0, 0,null);
monkey.draw(canvas);
}*/
}
Main Game Loop
package com.abc.apps;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainGameLoop extends Thread {
private SurfaceHolder surfaceHolder;
private MainGameBoard gameBoard;
private Monkey monkey;
private static final String TAG = MainGameLoop.class.getSimpleName();
// flag to hold game state
private boolean running = true;
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing on the surface
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
// update game state
// render state to the screen
// draws the canvas on the panel
gameBoard.render(canvas);
}
}
finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
public MainGameLoop(SurfaceHolder surfaceHolder, MainGameBoard gameBoard) {
super();
this.surfaceHolder = surfaceHolder;
this.gameBoard = gameBoard;
}
}//MainThread
Monkey Class
package com.abc.apps;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
public class Monkey {
private Bitmap bitmap; // the actual bitmap
private int x; // the X coordinate
private int y; // the Y coordinate
private boolean touched; // if monkey is touched
public Monkey(Bitmap bitmap, int x, int y) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public boolean isTouched() {
return touched;
}
public void setTouched(boolean touched) {
this.touched = touched;
}
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2), y, paint);
}
}
It looks like you are drawing your background in your MainGameBoard class in the render method.
public void render(Canvas canvas) {
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, 0,null);
monkey.draw(canvas);
}
You should just need 2 drawBitmap calls instead of 1 there.
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, y_offset1,null);
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, y_offset2,null);
I'm making an assumption that each background image has the same height or greater than the screen height; if it is less than the screen height you would need more than 2 instances.
Then you start 1 image at y_offset1 = 0 and the other at y_offset2 = -image_height.
Each draw you would increase y_offset1 and y_offset2 by the same amount. You would then need to do a check for both offsets to see if either has an amount greater than the screen height. If it does then the y_offset that is now "below screen" should be reset to the other y_offset minus the image_height. This will create a scroll image that loops indefinitely.
When using this type of technique it is important to think about your image edges; the image should be designed such that they tile seamlessly, otherwise at the looping point there is a noticeable visual artifact along the edge.

Create a counter in game android

I am doing a game .I want creat a counter .It begin from 200 and then 1s reduced about 0 .It my code :
public class GameView extends View{
private int count = 200;
private TimeCountThread timeCountThread;
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
timeCountThread = new TimeCountThread();
timeCountThread.start();
}
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.WHITE);
canvas.drawText("Time :"+count, 10, 35, paint);
}
public class TimeCountThread extends Thread{
public void run(){
while(count > 0){
try {
sleep(1000);
count--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public boolean onTouchEvent(MotionEvent event){
if(event.getAction()==MotionEvent.ACTION_DOWN){
int x1=(int) event.getX();
int y1=(int) event.getY();
Toast.makeText(getContext(), "x1 = "+x1+", y1 ="+y1,1).show();
}
return true;
}
}
Why the counter don't activity .Please help me?
Thanks
I want creat a counter .It begin from 200 and then 1s reduced about 0
You can achieve it by CountDownTimer
Try using a handler with a runnable inside of it. Such as:
Handler handler=new Handler();
Runnable r=new Runnable() {
public void run() {
count--;
if(count > 0) {
handler.postDelayed(this, 1000);
}
}
};
if(count > 0) {
handler.postDelayed(r, 1000);
}
where your
timeCountThread = new TimeCountThread();
timeCountThread.start();
is. Another problem might be that your count is private, but I don't think that that will make that big of a difference.

Making methods run continiously in android

I am making an android game that needs to run a method continiously, kind of like a timer. I need that it is being called every second. How can i make this possible???
Java code:
import java.util.ArrayList;
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.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;
import android.widget.Toast;
public class ExampleView extends SurfaceView implements SurfaceHolder.Callback
{
class ExampleThread extends Thread
{
private ArrayList<Parachuter> parachuters;
private Bitmap parachuter;
private Paint black;
private boolean running;
private SurfaceHolder mSurfaceHolder;
private Context mContext;
private Handler mHandler;
private GameScreenActivity mActivity;
private long frameRate;
private boolean loading;
public ExampleThread(SurfaceHolder sHolder, Context context, Handler handler)
{
mSurfaceHolder = sHolder;
mHandler = handler;
mContext = context;
mActivity = (GameScreenActivity) context;
parachuters = new ArrayList<Parachuter>();
parachuter = BitmapFactory.decodeResource(getResources(), R.drawable.parachuteman);
black = new Paint();
black.setStyle(Paint.Style.FILL);
black.setColor(Color.WHITE);
running = true;
// This equates to 26 frames per second.
frameRate = (long) (1000 / 26);
loading = true;
}
#Override
public void run()
{
while (running)
{
Canvas c = null;
try
{
c = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder)
{
long start = System.currentTimeMillis();
doDraw(c);
long diff = System.currentTimeMillis() - start;
if (diff < frameRate)
Thread.sleep(frameRate - diff);
}
} catch (InterruptedException e)
{
}
finally
{
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
protected void doDraw(Canvas canvas)
{
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), black);
//Draw
for (int i = 0; i < parachuters.size(); i++)
{
canvas.drawBitmap(parachuter, parachuters.get(i).getX(), parachuters.get(i).getY(), null);
parachuters.get(i).tick();
}
//Remove
for (int i = 0; i < parachuters.size(); i++)
{
if (parachuters.get(i).getY() > canvas.getHeight())
parachuters.remove(i);
}
}
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() != MotionEvent.ACTION_DOWN)
return false;
float x = event.getX();
float y = event.getY();
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
Toast.makeText(getContext(), "x=" + x + " y=" + y, 15).show();
return true;
}
public void setRunning(boolean bRun)
{
running = bRun;
}
public boolean getRunning()
{
return running;
}
}
/** Handle to the application context, used to e.g. fetch Drawables. */
private Context mContext;
/** Pointer to the text view to display "Paused.." etc. */
private TextView mStatusText;
/** The thread that actually draws the animation */
private ExampleThread eThread;
public ExampleView(Context context)
{
super(context);
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
// create thread only; it's started in surfaceCreated()
eThread = new ExampleThread(holder, context, new Handler()
{
#Override
public void handleMessage(Message m)
{
// mStatusText.setVisibility(m.getData().getInt("viz"));
// mStatusText.setText(m.getData().getString("text"));
}
});
setFocusable(true);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
return eThread.onTouchEvent(event);
}
public ExampleThread getThread()
{
return eThread;
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder)
{
if (eThread.getState() == Thread.State.TERMINATED)
{
eThread = new ExampleThread(getHolder(), getContext(), getHandler());
eThread.start();
}
else
{
eThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
eThread.setRunning(false);
while (retry)
{
try
{
eThread.join();
retry = false;
}
catch (InterruptedException e)
{
}
}
}
}
I need to add a function or a socalled "method", a public void or something like that, that should be called every second and should do the exact same code as the MotionEvent event method, the onTouchEvent.
Following Rob's commented link, consider (which is not the accepted answer, though) reviewing this from the Android Developer's site, Resources section: http://developer.android.com/resources/articles/timed-ui-updates.html
It describes how to use the android os Handler class to implement a timer, rather than using the Timer and TimerTask classes themselves.
This pretty much what you are looking for.
How to run a Runnable thread in Android?
It does sth every 1000ms using a thread.

Categories

Resources