Android postDelayed Handler Inside a For Loop? - java

Is there any way of running a handler inside a loop?
I have this code but is not working as it does not wait for the loop but executes the code right way:
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
//
for (int i = 1; i < 6; i++) {
handler.postDelayed(this, 5000);
}
}
};
// trigger first time
handler.postDelayed(runnable, 0);
Of course when I move the post delayed outside the loop works but it does not iterate nor execute the times I need:
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
//
for (int i = 1; i < 6; i++) {
}
// works great! but it does not do what we need
handler.postDelayed(this, 5000);
}
};
// trigger first time
handler.postDelayed(runnable, 0);
SOLUTION FOUND:
I need to use asyntask along with Thread.sleep(5000) in the doInBackground method:
class ExecuteAsyncTask extends AsyncTask<Object, Void, String> {
//
protected String doInBackground(Object... task_idx) {
//
String param = (String) task_idx[0];
//
Log.d(TAG, "xxx - iter value started task idx: " + param);
// stop
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//
Log.d(TAG, "xxx - iter value done " + param);
return " done for task idx: " + param;
}
//
protected void onPostExecute(String result) {
Log.d(TAG, "xxx - task executed update ui controls: " + result);
}
}
for(int i = 0; i < 6; i ++){
//
new ExecuteAsyncTask().execute( String.valueOf(i) );
}

Instead of using a for loop, you can let the Runnable instance call itself for a specific number of times. These calls will be posted to UI thread queue so, keep that in mind. Also, since the delay is quite large, make sure the event is still needed when you trigger it next time.
The following code should do it:
final Handler handler = new Handler();
int count = 0;
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "Run test count: " + count);
if (count++ < 5) {
handler.postDelayed(this, 5000);
}
}
};
// trigger first time
handler.post(runnable);

Here is a simple logic I made, without moving the for loop inside runnable.
for(int i = 1; i<=5; i++){
...
new Handler().postDelayed(() -> myFunctionToExecute() , i * 1000);
}
So whenever the loop iterates, it just extends the handler delay. And this way, you may achieve. I was searching for something similar, couldn't find anything, because in my case I already did the implementation of for loop, moving it inside the run() creates a mess

My solution to this problem if anyone has simmilar issues:
int count = 0;
public static void method(param1, param2, param3) {
Runnable r = () -> { //put method inside runnable
View view = listView.getChildAt(position); //action to be complete
if (view != null) { //if action is successfully complete
view.setSelected(true); //do something with this
} else { //do a looper
if (count < 10) { //limited looper to certain number
count++;
method(param1, param2, param3); //run the method again
}
};
Handler h = new Handler(); //create a new Handler and post above thread with it
h.postDelayed(r, 300);
}
Basically, I have created an if-else statement where else statement runs the same method with postDelayed() again for a limited number of trials.

This can be another solution
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
int i;
public void run() {
for (i = 1; i < 6; i++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
}
}, 0);
//Add some downtime
SystemClock.sleep(5000);
}
}
};
new Thread(runnable).start();

Related

Android: Can't Execute Handler.postDelayed inside a for / while loop without IndexOutOfBoundsException

I want to change the background of an ImageView programatically, but inside a for / while loop on a separate thread. In my example, I have 3560 ImageViews in an ArrayList called 'lights'. I want to change each one's background inside a loop after a short delay, i.e. one changes every second.
ArrayList<ImageView> lights = new ArrayList<>();
int numberOfLights = 3560;
I originally used this code, but there is the problem that 'i' must be declared final as it is being called from an inner class, impossible if i need it for the for loop ...
Handler h = new Handler();
for( int i = 0; i < numberOfLights; i++) {
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(i).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
Therefore I tried using a global variable:
Handler h = new Handler();
counter = 0;
for( ; counter < numberOfLights; counter++) {
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(counter).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
It is as though this counter is completely ignored, h.postDelayed runs even when the counter is more than numberOfLights, I've tried just normal Threads with a Thread.sleep call, resulting in 'Only the original thread that created a view hierarchy can touch its views' and also used the runOnUiThread method but having no luck.
Any help is much appreciated.
Use the for each loop. It's way more elegant than the traditional loop and in this case you can make the local variable final
for(final ImageView light: lights) {
h.postDelayed(new Runnable() {
#Override
public void run() {
light.setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
also, define handler as
Handler h = new Handler(Looper.getMainLooper());
in order to run the code on UI thread
Just make a new variable:
final int iCopy = i;
Then use that in your Runnable.
Handler h = new Handler();
for( int i = 0; i < numberOfLights; i++) {
final int iCopy = i;
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(iCopy).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
This however may not avoid the IndexOutOfBoundsException if lights is being modified in the mean time. In that case a range check or making a copy of the array or light would solve your issue.

Delaying a while loop

(Android) How can I make a loop waiting a short time (like half an sec.) before doing another loop?
void replaceText(String s)
{
doSomething1();
int x = 0;
while (x < 5)
{
doSomething2();
x++;
}
doSomething3();
}
So what I want is that my app "waits" a short time after the method doSomething2(). Google could't help me this time:D
You can try using a Handler
// Execute some code after 1 second have passed
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
doSomething2();
}
}, 1000);
if you want your while loop to be executed every 1000ms for example, you can do this:
final Handler handler=new Handler();
Runnable r=new Runnable() {
public void run() {
doSomething2();
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);
This will execute doSomething2() every 1000ms.
Specific to your example, you can try the following option as well:
void replaceText(String s)
{
doSomething1();
int x = 0;
while (x < 5)
{
Thread.sleep(100);
doSomething2();
x++;
}
doSomething3();
}
Note that since Thread.sleep stops the thread, make sure you run this function on a non-UI thread. A naive implementation for this will be:
void replaceText(String s)
{
final String str = s;
Thread thread = new Thread() {
#Override
public void run() {
// user str instead of s;
doSomething1();
int x = 0;
while (x < 5)
{
Thread.sleep(100);
doSomething2();
x++;
}
doSomething3();
}
};
thread.start();
}
Thread.sleep(500);
Will cause your code to sleep for half a second before continuing. Note that you will then need to handle the InterruptedException appropriately.

Why is not my handler executing?

I have the following code:
int x=0;
private void startTimerThread() {
System.out.println("enter");
System.out.println("percentage"+percentage);
System.out.println("x"+x);
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
for (x = 0; x>= percentage; x++ ) {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable(){
public void run() {
textpercentage.animate(x, x++);
System.out.println("enter"+x);
}
});
}
}
};
new Thread(runnable).start();
}
I am trying to animate digits on a textview using timely text view, however when I call startTimerThread from my code which is outside of onCreate neither do I get the text view to display not does the system.out execute. What do I miss here?
try like this
Handler handler = new Handler();
int delay=1000;
Runnable rann=new Runnable() {
#Override
public void run() {
//Write Your logic here which you want to perform periodically
System.out.println("Handler is running : ");
//to call the same thread repeatedly calling handler again
handler.postDelayed(rann, delay);
}
};
private void startHandler() {
//here the handler will executes the rannable after that particulary delay milli seconds
handler.postDelayed(rann, delay);
}
private void stopHandler() {
handler.removeCallbacks(rann);
}

using Thread multiple times for updating UI

I write some timer. and I want to display it in textview after start button is clicked.
What I did.
Every time I
timer = new Thread(new Runnable() {
#Override
public void run() {
while (!stopedButton ) {
time = "";
if (timerMinutes >= 60) {
timerMinutes = 0;
timerHours++;
}
if (timerHours < 10)
time = "0" + String.valueOf(timerHours) + ":";
else
time = String.valueOf(timerHours) + ":";
if (timerMinutes < 10)
time += "0" + String.valueOf(timerMinutes);
else
time += String.valueOf(timerMinutes);
runOnUiThread(new Runnable() {
public void run() {
if (!stopedButton) {
mTimeFromStartValue.setText(time);
timerMinutes++;
} else {
timerMinutes = 0;
timerHours = 0;
}
}
});
Log.e(TAG, ""+timerHours);
Log.e(TAG, ""+timerMinutes);
Log.e(TAG, time);
try {
Thread.sleep(1 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
so it works fine, but every time after stop and then start and after doing it many times my timer starts working fast. I try to avoid that kind of situation and I thought that i don't need to create new timer every time. But I need to have working timer after stop start too.
I wrote some code like this:
if(timer.isAlive()){
timer.resume();
}else{
timer.start();
}
But I have got this exception: java.lang.IllegalThreadStateException: Thread already started
so how to solve this ?
You need to create new Thread instance to start new thread. Also You need do use interrupt() method of Thread class.
Use this code to finish Your thread:
#Override
public void run() {
while (true) {
// Your code here
if(isInterrupted ()){
return;
}
}
}
Use this code when stop button was clicked:
timer.interrupt();
timer.join();

Android app that generates random words every second and displays them on screen

How can I make an android app that generates a random word every 1 second?
Here is my code:
new Timer().scheduleAtFixedRate(new TimerTask(){
public void run()
{
started = true;
word = "";
for (int i = 0; i < lenght+1; i++)
{
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
}
txt.setText(word);
}
}, 0, 5000);
It seems that my app stops every time it must change the text of the TextView("txt"); how can I make this work?
Undoubtfully, run this within a Thread. Doing this, it will generate the words in background and once it already has, the main UI thread must just append the content to the txt instance.
new Thread(
new Runnable() {
public void run() {
// your stuff
}
}
).start()
To assign the result to the txt object, you'll probably be unable to do it within this thread. To do so, you'll need to declare a Handler in your Activity and use that handler within your thread, so it uses sendMessage() to the main Activity and the Activity just sets the text.
More on this here and here.
---- EDIT ----
As #FD_ says, there is another way to do the update without the use of a Handler. You would just need to call the runOnUiThread() method, something like this:
runOnUiThread(new Runnable() {
public void run() {
txt.setText(your_new_text);
}
});
Another way is using an AsyncTask, which is (talking vaguely) an "evolution" of a thread which makes a lot of stuff for you. More on AsyncTasks here.
---- EDIT ----
This would be one of the ways:
new Thread(
new Runnable() {
public void run() {
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
started = true;
word = "";
for (int i = 0; i < lenght+1; i++)
{
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
}
// This will update your txt instance without the need of a Handler
runOnUiThread(new Runnable() {
public void run() {
txt.setText(word);
}
});
}
}, 0, 5000);
}
}).start();
try this:
int i = 0;
public void changeString() {
started = true;
word = "";
int j = rand.nextInt((max - min) + 1) + min;
word += tr.Translate(j);
txt.setText(word);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (i < lenght + 1) {
changeString();
i++;
}
}
}, 1000);
}
You can do this using timer as well
int i=0;
new Timer().scheduleAtFixedRate(new TimerTask(){
public void run()
{
started = true;
word = "";
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
txt.setText(word);
i++
}
}, 0, 5000);
try the above. The mistake you were making is using a for loop inside run instead use loop run method it-self.

Categories