Android: how to create delay in loop while still updating the UI - java

This is my first post here so sorry if I don't format my question correctly.
I am developing my first Android app and it is a card game. I've developed the same card game in C# using visual studio. In C#, in order to simulate action and delay when dealing, etc, I slept the thread for a given amount of time, then called the method Application.DoEvents() which forced the UI to update. However, in java, I cannot seem to find an answer to this problem.
I'll post some code from my deal() method, which I need to delay so it looks like the cards are actually being dealt in a circle, and not all at once since the computer goes so fast:
private void dealHelper()
{
Hand pCards = Referee.getHumanHand();
//show all cards in rotating order
for(int i=0; i<CARD_COUNT; i++)
{
///////////////////////////////////////////////////////////////////////
// load each card into their appropriate ImageViews and make visible //
///////////////////////////////////////////////////////////////////////
//human player
LoadCard(playerCards.get(i), pCards.getCard(i));
playerCards.get(i).setVisibility(View.VISIBLE);
playerCards.get(i).setPadding(1, 1, 1, 1);
// allow discarded cards to be clickable
discardCardImages.get(i).setPadding(1, 1, 1, 1);
//computer 1
computer1Cards.get(i).setImageResource(R.drawable.cardskin);
computer1Cards.get(i).setVisibility(View.VISIBLE);
//computer 2
computer2Cards.get(i).setImageResource(R.drawable.cardskin);
computer2Cards.get(i).setVisibility(View.VISIBLE);
//computer 3
computer3Cards.get(i).setImageResource(R.drawable.cardskin);
computer3Cards.get(i).setVisibility(View.VISIBLE);
}
}
I need a slight delay of about 500ms between each card that is displayed on the screen to simulate action. I've searched and searched and haven't a solution that works (or I understand). Any help would be much appreciated.
Thank You,
Daniel

Use a Handler with a Runnable (which does one iteration of the loop in its run()) and postDelayed(Runnable r, long delayMillis) for the delay. Count the iterations so you know when to stop and use the last one to removeCallbacks() and call a method to do whatever needs to be once the dealing is done.
Something like
private final Handler mHandler = new Handler();
private int iLoopCount = 0;
private final Runnable rDealAndWait = new Runnable()
{
public void run()
{
if (dealtAHand())
{
++iLoopCount;
mHandler.postAtTime(this, SystemClock.uptimeMillis() + DEAL_DELAY);
}
else
{
doAfterAllHandsDealt();
}
}
};
private boolean dealtAHand()
{
if (i == CARD_COUNT) return false;
//human player
LoadCard(playerCards.get(iLoopCount), pCards.getCard(i));
playerCards.get(iLoopCount).setVisibility(View.VISIBLE);
playerCards.get(iLoopCount).setPadding(1, 1, 1, 1);
// etc
return true;
}
And then in the onCreate or wherever
dealtAHand();
mHandler.postAtTime(rDealAndWait, SystemClock.uptimeMillis() + DEAL_DELAY);
}

Try out Thread.sleep(long millis). You'll have to put it in a try/catch block.

If nothing works out for you from above solutions, then give a try to CountDownTimer here,
http://developer.android.com/reference/android/os/CountDownTimer.html

please check my answer here it may help you. dont know its proper way or not but it worked for me very fine.
#Override
public void run() {
for(int i = 0;i<diceNum;i++){
runOnUiThread(new Runnable() {
#Override
public void run() {
//do your Ui task here
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Related

Delay execution of code in method Java

I want to generate random number after every 2 seconds in my java (Android) program continuously for at least 10 minutes. But I just want to pause/delay execution of code in only one method and not the whole program.
I tried using Thread like this -
boolean stop = false;
int random_number = 0;
while(true){
if(stop){ //if stop becomes true, then
return; //terminate the method
}
random_number = Math.random(); //generate random number
//which is used bu some other
//part of code
try {
Thread.sleep(2000); //delay the code for 2 secs
} catch(InterruptedException ex) { //and handle the exceptions
Thread.currentThread().interrupt();
}
}
However, this doesn't work as Thread.sleep stop the whole program execution instead on just stopping execution of code inside method and my whole screen becomes blank.
I also tried using Handler but it didn't work either as it doesn't stop execution of code in my method and instead just stack up.
This will demonstrate the working of it better -
while(true){
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
System.out.println("After 2 secs"); //this gets printed
//later
}
}, 2000);
System.out.println("Before 2 secs"); //this gets printed first
}
So the code stacks up making it equivalent to using while loop and make it incredibly slow.
Also, since I'm developing app for Android, I'm running on Java SE 6, so I can't use scheduleAtFixedRate. Is there any other way in which I can accomplish this?
Thanks a lot!
private Timer timer;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//Generate number
}
}, 2000, 2000);
//Documentation (From SDK)
/**
* Schedule a task for repeated fixed-rate execution after a specific delay
* has passed.
*
* #param task
* the task to schedule.
* #param delay
* amount of time in milliseconds before first execution.
* #param period
* amount of time in milliseconds between subsequent executions.
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0 || period <= 0) {
throw new IllegalArgumentException();
}
scheduleImpl(task, delay, period, true);
}
and when you want to stop it
timer.cancel()
Option 1: Using threads, you might run your job off the main (UI) thread:
new Thread(new Runnable() {
// some code here ...
// This might be in a loop.
try {
Thread.sleep(2000);
} catch(InterruptedException ex) {
// Handle ...
}
}
}).start();
Then, if this new thread you'd like to modify UI (i.e. show/hide button, display something on the screen etc), remember to pass that through the UI thread, as only this one can modify the UI. You might consider using Activity.runOnUiThread() for that.
Option 2: Another, more Android-style way of approaching that issue is to use AsyncTask. It contains three callbacks which can be used to do work on- and off- the UI thread. Sketch of such a code could look like:
private class MyTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
// This method is running off the UI thread.
// Safe to stop execution here.
return null;
}
protected void onProgressUpdate(Void... progress) {
// This methid is running on the UI thread.
// Do not stop thread here, but safe to modify the UI.
}
protected void onPostExecute(Long result) {
// Also on UI thread, executed once doInBackground()
// finishes.
}
}
Option 3: Then there is also a Timer, as suggested by #Stultuske. It's less flexible then AsyncTask, but handles the interval for you.
Depending on your needs, you can still accomplish what you seek with Handler.
You don't have to create/start the Handler in a while loop(which, as you noticed, just stacks up unless you stop the loop itself, but it is a nonsense).
Just create the Handler and tell him to post delayed your Runnable instance. In the Runnable at the very end you check your conditions. If it is still OK, then post another runnable delayed, else you do nothing and the Handler will have no more executions.
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
System.out.println("After 2 secs");
random_number = Math.random();
if (!stop) // should not be stopped, so we add another runnable;
{
handler.postDelayed(this, 2000);
}
}
handler.postDelayed(runnable, 2000);
The only downside is that Handler could freeze if the device is not used for a while, meaning it will start the counting back from where it left once the device screen is turned on.
It could do like 1 minute of correct work, then block at 1.4 seconds when the device is gone in sleep mode, and once it is turned on again, Handler would do the remaining 0.6 seconds.
Still, not knowing your needs you may be unaffected by this behavior and the answer may fit you.
if you want to use thread, do it like this :
Thread t = new Thread(){
public void run(){
while(true){
if(stop) break;
random_number = Math.random();
sleep(2000);
}
}
};
t.start();

Code not executed in expected order? [duplicate]

Visually, I'm expecting my app to show four Toasts in the following order:
createToast("start of delayed RandomCue Method");
createToast("start of delay");
createToast("end of delay");
createToast("end of delayed RandomCue Method");
However, the resulting order is:
createToast("start of delayed RandomCue Method");
createToast("end of delayed RandomCue Method");
createToast("end of delay");
createToast("start of delay");
My overall goal is to have a program that displays an image and changes ever 3 seconds. The player can press a button and the image changes for 1.5 seconds. Therefore, there are two methods, one to change picture using countdowntimer and another to change picture using onClick method corresponding to imagebutton.
The problem I'm running into is the code provided in the link (method called from within an onclick method) is supposed to change the image, set a bool value to false, wait 1.5 seconds, and then change the same bool value back to true.
While the bool value is true, the method that changes the pictures is supposed to be skipped but that's not the case and I don't know why but I think it's something to do with the code in the gists I created below.
So the issue I have is when the button is clicked, the image changes as expected but it sometimes changes again too quickly due to the first method not recognizing that the player responded and thus shouldn't change image yet.
public void delayedRandomCue(final long a){
didPlayerRespond = true;
createToast("start of delayed RandomCue Method");
randomCue();
Thread delay = new Thread() {
public void run() {
try {
createToast("start of delay");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
createToast("end of delay");
didPlayerRespond = false;
}
}
};delay.start();
createToast("end of delayed RandomCue Method");
}
https://gist.github.com/cjayem13/d32446ceb8c6d9626c68#file-easyfragment-Java
https://gist.github.com/cjayem13/d32446ceb8c6d9626c68
https://gist.github.com/cjayem13/d0a0b124dfe17666be25#file-easyfragment-Java
https://gist.github.com/cjayem13/d0a0b124dfe17666be25
onclick(){
delayedRandomCue(final long a)
}
randomCue();
Thread cueThread = new Thread(){
public void run() {
try {
while (fComm.fragmentGetTimerBool()) {
if(!didPlayerRespond) {
if (decTime > 1000) {
Thread.sleep(decTime);
} else {
Thread.sleep(1000);
}
decTime -= 50;
randomCue();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
saveScore();
}
// turn into end of all pics triggers bonus sTimerOn = false; fComm.fragmentScoreResponse(100);
//createToast("Bonus for completing all possible answers");
}
}; cueThread.start();
public void delayedRandomCue(final long a){
didPlayerRespond = true;
this happens first
createToast("start of delayed RandomCue Method");
randomCue();
Thread delay = new Thread() {
public void run() {
This happens in the background, asynchronously.
try {
createToast("start of delay");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
This happens in the background, after asynchronously running and completing
createToast("end of delay");
didPlayerRespond = false;
}
}
};delay.start();
This comes second because it is executed synchronously with the rest of the method.
createToast("end of delayed RandomCue Method");
}
This doesn't answer you question about the order of the toasts, but are you sure , when you say
The problem I'm running into is the code provided in the link (method
called from within an onclick method) is supposed to change the image,
set a bool value to false,wait 1.5 seconds, and then change the same
bool value back to true.
While the bool value is true, the method that changes the pictures is
supposed to be skipped but that's not the case and I don't know why
but i think it's something to do with the code in the gists I created
below.
that this is the case?
It looks more like , if the boolean is set to false, the other method that changes the pictures needs to be skipped, and as long as it is true, it needs to periodically change the pictures.
Try that, and maybe your image won't change very quickly after the user did trigger the onClick.

libgdx - doing something in other thread not working

My game has a stats queue, after each game the current game stats goes into the queue.
Whenever the mainmenu starts i want to upload all the game stats to a server, and this take like 1-3 seconds and I want to do this in an other thread.
My code
#Override
public void show() {
Global.key = Global.getKey();
// System.out.println(Stats.getJSONObject(Global.key));
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Stats.TryUploadGame1();
System.out.println("DONE");
}
});
.....
}
But this also freezes my game.
What should I do?
Your current code is posting a Runnable instance that will be executed by the render thread before the next frame. The Gdx.app.postRunnable API is generally used so background threads can ask for something to happen on the render thread. You want to post a Runnable to execute anywhere but the render thread.
As long as your Stats code doesn't interact with OpenGL context at all (since Android OpenGL APIs assume only a single thread interacts with them), you can just post your Runnable on a new background thread:
new Thread(new Runnable() { ... }).start();
This should unblock your render. (Of course, if your background thread uses a lot of CPU, it can still interfere with the render thread, but if its mostly doing blocking IO or host has spare cores, it shouldn't interfere.)
This could be improved in lots of ways (using a ThreadPool, or using Android-aware background task support), but if your stats update is relatively quick and the thread creation isn't frequent this should work fine.
Okay to do something in a other thread you need to take care of the OpenGL context. Inside of a different thread you cant do anything that does render stuff. You are forced to push such thing into the renderthread in any way. And you need to synchronize everything that can be called from the regular render thread from libgdx. For example you want to call the .act(float delta) from a stage from a different thread you are forced to put the stage indo an synchronized block.
The post runable isn't a thread. It is an runable that get executed at the beginning of the next rendercall. So it will stop the game till it's done but it is inside of the OpenGl context thread. (That's why your game stops)
So here is an example of how to use threading in libgdx. I use this inside of my game. It runs on 210 frames so 210 updatecalls per second. You can change it to as fast as possible or just to 60fps whatever you need:
public class GameLogicThread extends Thread {
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen) { //pass the game screen to it.
m_screen = screen;
setName("GameLogic");
}
#Override
public void run() {
m_runing = true;
Logger.log("Started");
while (m_runing) {
m_timeBegin = TimeUtils.millis();
// act of the camera
synchronized (m_screen.figureStage) { //stage with figures
// now figures
if (m_screen.m_status == GameStatus.GAME) {
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0) {
try {
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e) {
Logger.error("Couldn't sleep " + e.getStackTrace());
}
} else {
Logger.error("we are to slow! " + m_sleepTime); //meight create it dynamic so if you are to slow decrease the framerate till you are not to slow anymore
}
}
}
/**
* Stops the thread save<br>
*/
public void stopThread() {
m_runing = false;
boolean retry = true;
while (retry) {
try {
this.join();
retry = false;
}
catch (Exception e) {
Logger.error(e.getMessage());
}
}
}
}
This does update all my figures. To not cause any troubles with the rendering thread the figurestage is synchronized. (Kind of critical section)
Dont forget that you need to create a new thread every time you stopped it. so for example inside of the show you need todo this:
#Override
public void show() {
super.show();
m_logic = new GameLogicThread(this); //create a new one inside of the GameScreen
m_logic.start(); //start the thread
}
Also dont forget to savestop it inside of the pause stop and so on.
#Override
public void dispose() {
m_logic.stopThread();
}
According to the wiki
To pass data to the rendering thread from another thread we recommend using Application.postRunnable(). This will run the code in the Runnable in the rendering thread in the next frame, before ApplicationListener.render() is called.
So calling that method is just creating a new thread on to run on the render thread.
You may want to use standard java practice on creating threads unless this is frowned upon in libgdx because of android, that I am not sure of.

Order of execution lines of code

I don't get this :
In a ShakeListener class, I execute a routine in the containing class.
The routine is :
public void showWord(){
myShakeListener.stop();
flipper.showNext();
v.vibrate(countdown5, -1);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myShakeListener.start();
}
Strange thing (to me, still a beginner), is that the thread sleeps BEFORE the next view is shown. Why is that?
What I want to accomplish : user shakes phone -> viewflipper flips to next -> Phone is unresponsive to shaking for 5 seconds -> user shakes phone -> viewflipper flips to next...
thnx
The problem is that the viewflipper is probably another thread. You're hitting a race condition. Better option is to spawn a thread for 5 seconds that sets a boolean called something like "noshake" to true when it starts and sets it false it when it's done. Check if noshake == false before allowing another shake.
Does that makes sense?
It's because your code is blocking the UI thread. You should do something like this:
Handler mHandler = new Handler();
public void showWord(){
myShakeListener.stop();
flipper.showNext();
v.vibrate(countdown5, -1);
mHandler.postAtTime(new Runnable() {
#Override
public void run() {
myShakeListener.start();
}
}, 5000);
}

How can I schedule a background thread to play sounds in my app?

I have a process which should react on some events. So when playFromList() is called it plays some sound from soundpool. Then in a thread I set a flag and for 3,5 seconds it should not play any sounds.
What I got is: It plays sound and if than wait 3,5 seconds. If playFromList() is called 5 times in 3,5 seconds it still gets to SoundManager.playSound(listNr), and still is done in 17,5 seconds. And its not exactly what I wanted. I wanted method SoundManager.playSound(listNr) called only once.
public class Settings{
public static boolean flag = false;
}
public class Main{
public void playFromList(int listNr,int g){
if(!Settings.flag){
SoundManager.playSound(listNr);
if(g ==0){
mpVolume((float) 0.3);
t5sec.run();
}else{pauseMus();}
}
}
private Handler vijfSeconden = new Handler(){
public void handleMessage(Message msg){
mpVolume((float)0.8);
}
};
Thread t5sec = new Thread(){
public void run(){
if(Settings.flag == false){
Settings.flag = true;
try {
Thread.sleep(3500);
} catch (InterruptedException e) {
Settings.flag = false;
e.printStackTrace();
}
vijfSeconden.sendEmptyMessage(0);
Settings.flag = false;
}
}
};
}
There are few problems with the code. Probably most important thing that is strange is
t5sec.run(), in Java you you should use start method on the Thread object to start new Thread. As written it will execute in the calling thread.
Second problem is absolute lack of synchronization, one way to fix that, I guess, would be to use AtomicBoolean instead of boolean in Settings.flag
Another issue is that it is quite expensive to start new thread every time. It is a bit hard to tell from the description precisely what you want to do, but if my understanding is correct you should just do something like this:
if ( (System.currentTimeInMillis() - lastTimePlayed) < 3500) {
playSound();
lastTimePlayed = System.currentTimeInMillis();
}
that's it and no threads required. You might want to use AtomicInteger to hold lastTimePlayed value if you want your class to be thread safe.

Categories