9

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) );

        }
Ivan Juarez
  • 1,413
  • 4
  • 21
  • 30
  • if you call `postDelayed` N times the `Runnable` will be run N times, isn't it what you want? – pskink Aug 18 '16 at 17:54
  • Yes, but it does not wait and triggers the code immediately which is something I dont want – Ivan Juarez Aug 18 '16 at 18:00
  • change `5000` to `5000 + i * 1000`, so the first `Runnable` will be run after 5 sec, the second after 6 sec etc... 7, 8, 9, ... – pskink Aug 18 '16 at 18:01
  • your answer is fine , but is not working either, it does not wait. – Ivan Juarez Aug 18 '16 at 18:08
  • wait for what? it is a "delayed" execution, what do you want to wait for? – pskink Aug 18 '16 at 18:09
  • I need "runn test" to be called every 5 secs – Ivan Juarez Aug 18 '16 at 18:10
  • so call once `handler.postDelayed(this, 5000);` inside your `Runnable` – pskink Aug 18 '16 at 18:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/121283/discussion-between-ivan-juarez-and-pskink). – Ivan Juarez Aug 18 '16 at 18:13
  • I dont think anyoness gonna click that link.. @IvanJuarez – cunniemm Aug 18 '16 at 18:24
  • @cunnniemm technicaly what I need to do is not achieved with psking examples, I do actually know how to work with handlers but what I need to do is to execute code inside it and at the same time get the index value of every iteration (and wait over every iteration), but I am realizing is not possible this way, that is why I am thiking of using a ThreadPoolExecutor. – Ivan Juarez Aug 18 '16 at 18:41
  • I need to run multiple instances of a task, each one in parallel and I need the ThreadPoolExecutor to execute each one of them separately, I have used AsyncTask but I was unable to run it because I have another handler inside doinbackground, I tried adding a looper and worked but had a mess of code, that is Why I am trying to achieve it with a simple handler and starting off with this example. – Ivan Juarez Aug 18 '16 at 18:56

4 Answers4

26

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);
Shaishav
  • 5,282
  • 2
  • 22
  • 41
  • When doing if(count++<6) it actually increase the count value by one? Or is it like if(count+1<6) ? – DAVIDBALAS1 Aug 18 '16 at 18:01
  • 1
    @DAVIDBALAS1 It will compare the current value to 6 and then increase the value for next iteration – Shaishav Aug 18 '16 at 18:03
  • So if it will compare the current value so your code will run 0,1,2,3,4,5 meaning 6 times and his code will run only 5 times , not? Just trying to learn.. – DAVIDBALAS1 Aug 18 '16 at 18:05
  • @DAVIDBALAS1 true :) ...didn't see that...I thought he started from 0...thanks – Shaishav Aug 18 '16 at 18:06
3

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

Aziz
  • 1,976
  • 20
  • 23
2

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.

Androidz
  • 261
  • 2
  • 11
2

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();
Hasan El-Hefnawy
  • 1,249
  • 1
  • 14
  • 20