How to use multiple postDelayed handlers - java

Hi I am new to android delveloping and I am curently making a simple game that tests your reflection when a certain color changes, to test what I have learned so far but I cant solve a problem that came up.
Alright, first I will explain how the game works:
When you tap the screen there is a random delay and after that you need to tap the screen again as quick as possilbe to get the best score, and if you tap earlier than when the delay is over the game stops and tells you to try again.
My problem is that when I tap for the second time no matter if that is after or erlier the delay it repeats a part of a code and I cant figure out why.I posted my code that is relevant to this below.Also if you need any decleration let me know!
P.S I thing that it has somenthing to do with the handlers but i'm not sure.
final Random random = new Random();
final int randomNumber = random.nextInt(10) + 1;
bestScoreView.setText("best score " + bestTime + " ms");
mainThing.setText("Tap to start");
mainThing.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
randomTimeDelay = randomNumber * 1000;
if (previousTapDetected){
mainThing.setText("You taped too fast");
mainThing.setBackgroundColor(ContextCompat
.getColor(getApplicationContext(), R.color.red));
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mainThing.setText("Try again");
}
}, 750);
}else if (previousTapDetected = true){
mainThing.setText("Wait for the color to change");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
previousTapDetected=false;
mainThing.setText("Tap now");
startTime = System.currentTimeMillis();
mainThing.setBackgroundColor(ContextCompat
.getColor(getApplicationContext(), R.color.red));
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mainThing.setText("You scored " + score + " ms");
mainThing.setEnabled(false);
}
}, 500);
}
}, randomTimeDelay);
endTime = System.currentTimeMillis();
score = endTime - startTime;
if (bestTime > score) {
bestScoreView.setText("Best score: " + score + " ms");
bestTime = score;
} else if (bestTime < score){
bestScoreView.setText("Best score " + bestTime + " ms");
}
}
}
});

As per the docs
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
And, in your code, you are trying to manipulate the UI elements, so the Handler should be created on the UI Thread
Handler handler = new Handler();
mainThing.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
randomTimeDelay = randomNumber * 1000;
if (previousTapDetected){
mainThing.setText("You taped too fast");
mainThing.setBackgroundColor(ContextCompat
.getColor(getApplicationContext(), R.color.red));
handler.postDelayed(new Runnable() {
#Override
public void run() {
mainThing.setText("Try again");
}
}, 750);

Related

Delay inside for loop

Hi I want to implement such behaviour:
Every one second I want to get a String from List and print it.
(actually I want my view to: setVisibility(View.Visible), but it's the same thing.
final Handler handler = new Handler();
for (String str : layoutsList) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("LevelOneFragment", "tick" + str);
i++;
}
}, 1000);
}
But this solution don't work.
How should I correctly do this?
Right now you are setting a delay for all work on the Handler at 1000ms. That means that each item of work will occur essentially at the same time, since the loop executes quickly.
Instead, why don't you try scheduling each item of work at an increasing delay, such as (i+1)*1000?
for (int i = 0; i < layoutsList.size(); i++) {
final String str = layoutsList.get(i);
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("LevelOneFragment", "tick" + str);
}
}, (i+1)*1000);
Why do you want to block the UI thread? :-(
for (String str : layoutsList) {
Log.d("LevelOneFragment", "tick" + str);
i++;
Thread.sleep(1000);
}

How do I delay a method in a for loop in java?

I am having trouble delaying the method assign_backgrounds() within a for loop. I am trying to create a Simon says game, but instead of delaying and showing the next button that "Simon" presses, it shows all the buttons at once. Any help here would be greatly appreciated. Thanks.
boolean simonsTurn = true;
int x = 4;
int s;
int delay = 1000;
int array_values[] = new int[]{1,2,3,4};
public void simonSays() {
// running = true;
if (simonsTurn == true) {
go();
for (int i = 0; i < x; i++) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
go();
}
}, 1000);
}
}
}
public void go(){
s = random_int_between(0,3);
assign_backgrounds(array_values[s]);
}
public void assign_backgrounds( int array_values ){
Handler handler = new Handler();
if( array_values == 1){
button1_.invalidate();
button1_.setBackgroundResource(R.drawable.goatclicked);
button1_.refreshDrawableState();
handler.postDelayed(new Runnable(){
public void run(){
button1_.invalidate();
button1_.setBackgroundResource(R.drawable.goat);
button1_.refreshDrawableState();}}, 1000);
}
else if( array_values == 2){
button2_.invalidate();
button2_.setBackgroundResource(R.drawable.pigclicked);
button2_.refreshDrawableState();
handler.postDelayed(new Runnable(){
public void run(){
button2_.invalidate();
button2_.setBackgroundResource(R.drawable.pig);
button2_.refreshDrawableState();}}, 1000);
}
else if( array_values == 3){
button3_.invalidate();
button3_.setBackgroundResource(R.drawable.chickenclicked);
button3_.refreshDrawableState();
handler.postDelayed(new Runnable() {
public void run() {
button3_.invalidate();
button3_.setBackgroundResource(R.drawable.chicken);
button3_.refreshDrawableState();}}, 1000);
}
if( array_values == 4) {
button4_.invalidate();
button4_.setBackgroundResource(R.drawable.cowclicked);
button4_.refreshDrawableState();
handler.postDelayed(new Runnable(){
public void run(){
button4_.invalidate();
button4_.setBackgroundResource(R.drawable.cow);
button4_.refreshDrawableState();}}, 1000);
}
}
It's because you are creating handlers very fast and then they are all starting at the same time. You should look into how Handler's work and about Asyncronous/Background tasks.
Now back to your problem, you are calling the a loop and it is creating handlers all in a row and they are being created very fast (nanoseconds). They will then all launch 1 second from that creation time because of your postDelayed() call. This is why everything is popping up at the same time! All of these delay posts are being executed at almost the same time on concurrent background threads.
Instead of a for(int i,...) loop you want to have a global int i, just add it to the top of the file.
At the end of any of Simon's turn you'll want, inside of the if, else if statement inside assign_background (at the end of the Runnables, then you'll want to call go().
This might cause problems because you are trying to access the main thread from all these background threads. so you might have to call the function runOnMainUIThread() as a quick hack when you call the go function.
All in all, you are going to have some problems until you understand Handlers, Background Processes, and Threads. Definitely great knowledge to learn about and Android has solid documentation on it just FYI.

Making a stopwatch using timer for javafx

I actually have a video streaming application and I want to show the time for how much the two people have chatted with eachother. I have used Timer and TimerTask of java.util class but it gives error as "Not on FX application thread" which means I cant setText to a java fx component using swing thread. This is what I have tried so far:-
int timerx=0 //global variable
private void timer(){
/*SHOWING TIME PASSED*/
int x=0;
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
System.out.println("working");
setTime();
}
};
timer.schedule(timerTask, 50, 50);
}
And updating the javafx Label as:-
private void setTime(){
timerx = timerx +1;
Platform.runLater(new Runnable(){
public void run(){
time.setText(String.valueOf((timerx)));
System.out.println(time.getText());
}
});
}
I think the main problem is javafx component not being able to update and be accessed from swing thread. I would be glad to get any kind of help.
Thank you
You can use something like this:
long timeStart = System.currentTimeMillis();
when the chat start and get how long two guys chatted with something like this:
long timePassed = System.currentTimeMillis() - timeStart;
This will get you how many millisecond have passed. If you want to get second divide it by 1000. Oh and if you want it on thread, just create a thread for this thingy..
ok thank you all for your answers. I solved my problem by running a thread and using algorithm that will show the time in 00:00:00 format which I wanted to make. Here is the code
private void startTime(){
if(timerStats==false)
{
timerStats = true;
timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
System.out.println("working" + x);
timersec ++;
Platform.runLater(new Runnable(){
public void run(){
if (timersec == 60)
{
timersec = 0;
timermin++;
}
if (timermin == 60)
{
timermin = 0;
timerhr++;
}
String seconds = Integer.toString(timersec);
String minutes = Integer.toString(timermin);
String hours = Integer.toString(timerhr);
if (timersec <= 9)
{
seconds = "0" + Integer.toString(timersec);
}
if (timermin <= 9)
{
minutes = "0" + Integer.toString(timermin);
}
if (timerhr <= 9)
{
hours = "0" + Integer.toString(timerhr);
}
time.setText(hours + ":" + minutes +":"+ seconds);
System.out.println(time.getText());
}
});
}
};
timer.schedule(timerTask, 50, 50); //lastone is time, milli second
}
}
Thank you

Call method after delay

I've crated Log in screen, and if user mistake 3 times i want to show timer of 2 min. I want that timer to be visually shown on the screen. I'll try this code and it's work, but I don't know how to display timer on screen.
Handler handler = new Handler();
long waitingTime = 2 * 60 * 1000; // 2 min
handler.postDelayed(new Runnable() {
#Override
public void run()
{
//Do something after 2 min
}
}, waitingTime);
You need to have Handler called every second and update the UI during every pass. When you reach 2 mins you can cancel the handler.
Code should be like this:
final Handler handler = new Handler();
//class variable
count = 0;
handler.post(new Runnable() {
#Override
public void run() {
updateCounter(count++);
if(count < 120) {
handler.postDelayed(this, 1000);
}
}
});
And function to update counter:
private void updateCounter(final int count) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// you have the seconds passed
// do what ever you want
}
});
}
you need use runOnUiThread(Runnable action)

How to Stop Recursive Call Of Handler?

I created a handler, to imitate timer task.
because TimerTask was acting differently on different tablets.
so I created this handler method.
in timer there was a method timerTask.cancel();
but how to stop this handler
it keeps on running even after the application is exited.
as you can see logs running even after back press.
Handler handler = new Handler();
public void recursivelycallHandler(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
recursivelycallHandler();
}
}, 100);
}
There are 3 methods to do that ..
handler.removeCallbacks(Runnable r);
handler.removeCallbacksAndMessages(null);
handler.removeMessages(int what)
In your case first two seem feasible .. add any of the above method in ondestroy or on a listener to backpress..
By putting any condition
Handler handler = new Handler();
int i = 0;
Runnable myRunnable = new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
if(i>5)
handler.removeCallback(myRunnable);
else{
i++;
handler.postDelayed(myRunnable, 100); // here is self calling
}
}
};
}
handler.postDelayed(myRunnable, 100);
Its recursive method but you can call the same Runnable object in run() instead of recursive method and remove that object when based on specific situation/condition
You can store flag (boolean var) to detect if you need to call for your handler and before exit app change this flag to false and stop calling handler.
you can do something like this below:
public void recursivelycallHandler(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
if(YOUR_CONDITION){
recursivelycallHandler();
}
}
}, 100);
}
Hope you got my point.
feel free to comment.
just add isFinished to your run method:
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (isFinished())
return;
Log.d("handler is running", "true" + System.currentTimeMillis());
recursivelycallHandler();
}
}, 100);

Categories

Resources