I want to make a loop, the times the user wants but with a delay of 3 seconds.
This is the code:
for (i = 0;i < n1; i++){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(KeyMapCreator.this, "Try number " + i,Toast.LENGTH_SHORT).show(); ActionIwantToDo();
}
},3000);
}
The variable i is the one that the user sets.
The problem is that the toast doesn't show up every 3 seconds, it just do like a normal loop without delay. I thought it was because of the time of the toast but if i set the time to 20 secs still being the same.
Someone knows how to make a proper delay inside a loop???
The problem you have is that your loop creates many handlers at once that delay for 3 seconds and then show a toast. They do not wait for each other, and because they are created within milliseconds of each other they will show the toast at the same time.
I'm not sure what you are trying to accomplish, and a loop is probably not what you want. However this is a way to get the toast to display after 3 seconds and every 3 seconds after for a number of times.
For this we will use recursion because it will make it so that you are not blocked on the main thread.
Call doSomething (the recursive function) from where you need the function to start (remember that the second variable is the number of times you want it to run, and 0 is just required as a counter)
doSomething(0, 3)
create doSomething
private void doSomething(int i, int n) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (i < n) {
Toast.makeText(KeyMapCreator.this, "Try number " + i,Toast.LENGTH_SHORT).show();
actionIWantToDo();
doSomething(i+1, n);
}
}
}, 3000);
}
A Handler just schedules some work for later execution. It doesn't actually block the current thread. All you're doing is scheduling n1 items of work to execute three seconds later, which will all execute in sequence on that exact delay.
You don't really ever want to write code to block the main thread. Ever. It will make your app appear to be unresponsive.
Related
I'm aware or the Thread.sleep() and postDelayed() function in java/androidStudio.
But here is the issue, I'm creating a replicate of Simon says game.
I created a generateSequence() function that puts number of 1-9 randomly into an array called sequence. After that, I need to display these sequence, which basically changes the background of a textView for a second and then back to its original background using the postDelayed() function.
Here is my code:
private void displaySequence(){
for(int i = 0; i < sequence.size(); i++) {
if(sequence.get(i) == 1) {
viewCard11.setBackgroundResource(R.drawable.text_view_circle4);
proceed = false;
handler.postDelayed(() -> {
viewCard11.setBackgroundResource(R.drawable.text_view_circle3);
proceed = true;
}, 1000);
}
else if(sequence.get(i) == 2) {}
else if(sequence.get(i) == 3) {}
else if(sequence.get(i) == 4) {}
else if(sequence.get(i) == 5) {}
else if(sequence.get(i) == 6) {}
else if(sequence.get(i) == 7) {}
else if(sequence.get(i) == 8) {}
else if(sequence.get(i) == 9) {}
while(!proceed) {}
}
}
But the problem with postDelayed() is that only whatever is inside the function is delayed. Meaning if this sequence had 2 element, it will simultaneously blink the background. The for loop doesn't wait for the postDelayed to finish whatever it is suppose to do, but instead it increments and proceed to put the next postDelayed.
To solve this issue, I tried to use a proceed boolean variable as a delay. What I do is that, before we call the postDelayed, I set proceed as false. Since it will not wait for postDelayed(), it will go to the next line of code which is the while loop.
By setting the proceed as false, I use it to create a infinite loop. But this infinite loop will be broken by the completed postDelayed() as proceed will be set to true in it, then the code can continues the for loop.
But I not sure why it simply doesn't work. When I run the code, it just displayed a blank screen. It seemed like the problem resides within the infitine while loop and postDelayed() can't update the proceed variable.
I tried using Thread.sleep(1000) as a replacement of postDelayed, but during startup, the program simply shows a white background for however long the parameter is passed to Thread.sleep()
I have exhausted my option and I hope someone has a better idea.
Thank you.
The loop does not wait for the postDelayed because what's inside the postDelayed happens async. This means that it works independently from the UI thread, on a second thread. What you want to accomplish is to make the UIthread wait for a period of time, and not start another thread after a specific period.
You could try to use the handler in this way:
Handler handler=new Handler()
{
public void handleMessage(Message msg)
{
if(msg.what==0)
{
viewCard11.setBackgroundResource(R.drawable.text_view_circle3);
proceed = true;
}
}
};
and then you may use the handler like this:
handler.postDelayed(() ->
{
//does nothing just waits 1 second and then send empty message
handler.sendEmptyMessage(0)
}, 1000);
I am almost a beginner on android. I am sort of stuck at a point. In the following code I am running a while loop for 30 times and runnable post delay is 3 seconds, means loop will run for 90 seconds(which is not important yet). It does so, thats fine. But in the runnable, when I call rangeofRouter0() function,the value in the textView changes to "You have reached the turn" when it goes into "else if" condition of rangeofRouter0() function and it must remove the callbacks as defined and move to next activity, exitiing from the while loop whether it has completed 90 seconds or not but program doesn't reach in if(textView.getText.equals....) part. And if I put this condition directly into "else if", callbacks are (I think) not removed and next screen is called again and again. I want that when code goes into else if, it should simply move to next screen and previous activity(means this activity), should simply be forgotten
int i = 1;
while (i<30)
{
myRunnable =new Runnable() {
public void run() {
scanWifiList();
rangeofRouter0();
}
};
handler1.postDelayed(myRunnable, i * 3000);
i++;
if(textView.getText().toString.equals("You have reached the turn")){
///this text gets in textView in "else if" condition
handler1.removeCallbacks(myRunnable);
Intent intent = new Intent(getApplicationContext(), FrontScreen.class);
// finish();
startActivity(intent);
break;
}
}//While loop ended
private void scanWifiList() {
mainWifi.startScan();
wifiList = mainWifi.getScanResults();
textView5.setText("" + firstRouterDistance());
}
public void rangeofRouter0(){
if(firstRouterDistance() >= 30 &&
firstRouterDistance() <= 70 && ((degree>0 && degree <60)||(degree>300 && degree <360)))
{
textView.setText("Move left");
speakOut(textView.getText().toString());
}
else if(firstRouterDistance() >= 3 &&
firstRouterDistance() <= 20 &&
secondRouterDistance() >= 7 &&
secondRouterDistance() <= 60 && degree>220 && degree <250)
{
textView.setText("You have reached the turn");
counter++;
}
else{
textView.setText("Not before dining hall");
}
}
You first need to understand how postDelayed() works exactly.
When you assign a runnable to the Handler's postDelayed(), that means you are scheduling a task to get executed at a particular time interval from the current time.
Now what you are doing is running a while loop 29 times and each time scheduling the task - total 29 tasks to run at 3,6,9... seconds respectively.
At this point you only scheduled the task and it's not started running yet.
And you while loop finishes after iterating for 29 times.
Your rangeofRouter0() never gets called during the while loop iterations since it took only a few milliseconds and hence counter is never greater than 0.
Note - If you want the loop to run for 30 times you should change it to while (i<=30).
So, you need to change your logic to achieve what you want. If you want to read more about Handler. Check this.
I set up a timer to perform a task every 10 seconds within a loop. Also, this is inside a broadcastReceiver, not the MainActivity.
doSomething() {
public void onSuccess(int[] arr) {
for (int i = 0; i<arr.length(); i++) {
<wait 10 seconds>
<show some message>
} // if i == 3, the loop should take 30 seconds to perform
}
}
I tried creating a new thread AND making a timer, but neither solution waits ten seconds for a task inside a loop. I have also tried doing Thread.sleep(10000) without creating a new thread, but this makes the main UI freeze for ten seconds before each task is performed. Could anyone lead me to the right direction?
Edit: this is a possible duplicate of this. My question, in other words, is that is it not possible to do a delayed task inside a loop? If so, why?
try this one count down timer http://developer.android.com/reference/android/os/CountDownTimer.html
Below I have a Runnable "updater" ...and an OnClick function that uses Handler.PostDelayed function to run the runnable after a delay...
After a little editing, cutting of useless parts here are the functions:
(passtog = Toggle Button)
final Runnable updater = new Runnable() {
#Override
public void run() {
if (passTog.isChecked()) {
now = System.currentTimeMillis();
time = now - init;
if (time > 5000) {
Toast.makeText(getApplicationContext(), "WAKE UP !",
Toast.LENGTH_SHORT).show();
}
handler.postDelayed(this, 25);
}
}
};
passTog.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
init = System.currentTimeMillis();
flag = true;
handler.postDelayed(updater,
(new Random().nextInt(4000) + 3000));
}
});
}
Explaination
Basically, The user toggles the Toggle button. Now it's on: The runnable can run completely (Everything is in the if block).
If the user doesn't press the button again, and switches it off The app sends a Toast "Wake Up!" ..It runs and checks every 25 millisecs to update the time...
Pretty straightforward... Yet I'm having a problem.
Before the program actually gets to the runnable, I absolutely NEED there to be a minimum time delay of 3 seconds + Some Random value ... So it varies between 3 sec - 7 sec. It SHOULD vary between 3-7 , but it doesn't.
When I run it: The problem
I notice that the first time, it works great... I get atleast a 3 sec delay + a random value= Perfect
The second time, that is after the switch goes on ->off-> on : Now It acts like it doesn't see the +3000 ...and just the ~randInt(4000) function... So it may give 0 sec or it may give 4 sec delay...
In all my experience, I've never really come across this.. I've rewritten the entire code, My other apps use this function in exactly the same sytax and seem to do pretty great.. Why is this creating a problem ? Could the Toast's time possibly be causing a problem..
How to solve this ?
(I'm open to other methods, preferably quick to implement. I want a minimum 3 sec delay which I'm not getting for some reason... I need the UI to be responsive though So no thread sleeping.)
You probably should call Handler.removeCallbacksAndMessages(null) when the switch goes off.
As the question says, here's the code.
What I want to do basically is I have a list of array, says "myArray". This array contains stored time points in millisecond. Next thing is I want to call a method based on those time points. So, I need to run a time counter from 0 while the music is playing, compare the time counter with the time points in the array progressively (from first array index until finished).
The first method "timeCounter" is a method to start a time counter while a music is playing through MediaPlayer.
public void timeCounter(){
Runnable myRunnable = new Runnable(){
#Override
public void run(){
while(musicPlaying){
startCounter(arrayPos);
}
}
};
Thread musicPlayer = new Thread(myRunnable);
musicPlayer.start();
}
This is where the comparison of time counter and time in the array takes place.
public void startCounter(List<Long> array){
elapsedTime = System.currentTimeMillis() - timeStart;
if(elapsedTime == array.get(arrayPos)){
arrayPos += 1; //Continue comparing with the next number in the array
Log.v("DEBUG", "TIME MATCHES!");
if(arrayPos>= array.size()){
arrayPos= 0; //Prevent out of array index
}
}
}
I have the code running correctly and the result from the LogCat is correct.
Now the problem is sometimes the Thread is not running until the music finished playing (I have set onCompletionListener and set "musicPlaying" to false when music finished). The stopping point is totally random, sometimes when it's just started, or around 50%, or even when it's near to completion. Sometimes it doesn't even start!
I've been trying to figure out why but I couldn't find any info about Thread stopping halfway or such in anywhere. Thanks in advance! =)
If musicPlaying is modified and read between threads, make sure it is declared volatile.
I suspect your if(elapsedTime == array.get(arrayPos)) should be if(elapsedTime >= array.get(arrayPos)).
You need to remember that the millisecond timer does not necessarily have a one millisecond tick. On Windows, for example, the returned value will only change every 15 ms or so. You may therefore completely miss a particular time and therefore never get past that entry in your list.