35

I need to perform some code in regular intervals (connect to a server and pull data from MySQL database every minute). For this purpose I have a Sync class:

public class Sync {

    static private Handler handler = new Handler();
    Runnable task;

    public Sync(Runnable task, long time) {
        this.task = task;
        handler.removeCallbacks(task);
        handler.postDelayed(task, time);
    }
}

and in my Activity I have:

public void onCreate(Bundle savedInstanceState) {
    ...
    Sync sync = new Sync(call,60*1000);
    ...
}

final private Runnable call = new Runnable() {
    public void run() {
    //This is where my sync code will be, but for testing purposes I only have a Log statement
    Log.v("test","this will run every minute");
    }
};

I have tried this with a shorter time period for testing, but It only runs once. When it Logs the message for the first time, its also the last. Does anyone see what Im doing erong here? Thanks!

5 Answers5

59

You can do that using the below code, Hope it helps!

final Handler handler = new Handler(); 
Runnable runnable = new Runnable() { 

    @Override 
    public void run() { 
        try{
            //do your code here
        }
        catch (Exception e) {
            // TODO: handle exception
        }
        finally{
            //also call the same runnable to call it at regular interval
            handler.postDelayed(this, 1000); 
        }
    } 
}; 

//runnable must be execute once
handler.post(runnable);
java acm
  • 1,020
  • 12
  • 24
MKJParekh
  • 34,073
  • 11
  • 87
  • 98
  • 2
    Yep this is what I was going to say. AlarmManager is heavier and require handling Intents to trigger your Runnable. Having your Runnable re-post itself at the end if the way to go. And you should wrap your code in the Runnable with a try-finally and repost the Runnable in the finally section, to make sure it's never skipped. – Greg Apr 18 '12 at 10:46
  • 27
    I think that the `handler.postDelayed(this, 1000);` should be only on the finally section (not at the end of the try block), otherwise it will be posted two times. – Parmaia Feb 21 '14 at 10:59
  • 1
    @amram99 your edit was rejected by others but I find it correct so updated as you suggest. Parmaia Thanks for comment. – MKJParekh May 06 '16 at 12:04
  • 1
    While this answer would have been valid at the time it was answered. If you need to fetch data at specific interval, you should now be using Firebase Job Dispatcher. One of the reason is that it can help your users save battery (depending on parameters you set) and you don't need to worry about your services being killed when in background by OS on Android O+ – Milan Sep 06 '17 at 16:28
8

First you have to declare handler globally Second you have to use post Delay method again in runnable to trigger it again.

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Sync sync = new Sync(call,60*1000);

    }
    final private Runnable call = new Runnable() {
        public void run() {
        //This is where my sync code will be, but for testing purposes I only have a Log statement
        Log.v("test","this will run every minute");
        handler.postDelayed(call,60*1000);
        }
    };
    public final Handler handler = new Handler();
    public class Sync {


        Runnable task;

        public Sync(Runnable task, long time) {
            this.task = task;
            handler.removeCallbacks(task);
            handler.postDelayed(task, time);
        }
    }


}
Maneesh
  • 6,098
  • 5
  • 36
  • 55
3

handler.postDelayed(task, time); will only execute once, if you want the code to trigger at regular intervals I would suggest a Timer and a TimerTask instead of a Handler and a Runnable.

TimerTasks can be set to run once, every x seconds, or with a fixed period e.g. x seconds - however long it took to run last time.

ScouseChris
  • 4,377
  • 32
  • 38
2

An alternative way, using ScheduledExecutorService's scheduleAtFixedRate:

private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

public void beepEvery10Seconds() {
     final Runnable beeper = new Runnable() {
       public void run() { System.out.println("beep"); }
     };
     final ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(beeper, 0, 10, SECONDS);
}
laffuste
  • 16,287
  • 8
  • 84
  • 91
1
      private void doSomethingRepeatedly() {
      timer.scheduleAtFixedRate( new TimerTask() {
            public void run() {

                  try{

                   //Your code

                  }
                  catch (Exception e) {
                      // TODO: handle exception
                  }

             }
            }, 0, 10000);
                     }
ritesh4326
  • 687
  • 7
  • 9