14

First of all, I could not even chose the method to use, i'm reading for hours now and someone says use 'Handlers', someone says use 'Timer'. Here's what I try to achieve:

At preferences, theres a setting(checkbox) which to enable / disable the repeating job. As that checkbox is checked, the timer should start to work and the thread should be executed every x seconds. As checkbox is unchecked, timer should stop.

Here's my code:

Checking whether if checkbox is checked or not, if checked 'refreshAllServers' void will be executed which does the job with timer.

boolean CheckboxPreference = prefs.getBoolean("checkboxPref", true);
                if(CheckboxPreference == true) {
                    Main main = new Main();
                    main.refreshAllServers("start");
                } else {
                    Main main = new Main();
                    main.refreshAllServers("stop");
                }

The refreshAllServers void that does the timer job:

public void refreshAllServers(String start) {

    if(start == "start") {

        // Start the timer which will repeatingly execute the thread

    } else {

        // stop the timer

            }

And here's how I execute my thread: (Works well without timer)

Thread myThread = new MyThread(-5);
                myThread.start();

What I tried?

I tried any example I could see from Google (handlers, timer) none of them worked, I managed to start the timer once but stoping it did not work. The simpliest & understandable code I saw in my research was this:

new java.util.Timer().schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
            }
        }, 
        5000 
);
sarkolata
  • 370
  • 2
  • 7
  • 17
  • 1
    See if the answer [here](http://stackoverflow.com/questions/8098806/where-do-i-create-and-use-scheduledthreadpoolexecutor-timertask-or-handler/8102488#8102488) helps. – yorkw Jul 24 '12 at 21:26

5 Answers5

40

Just simply use below snippet

private final Handler handler = new Handler();
private Runnable runnable = new Runnable() {
    public void run() {
         //
         // Do the stuff
         //

         handler.postDelayed(this, 1000);
    }
};
runnable.run();

To stop it use

handler.removeCallbacks(runnable);

Should do the trick.

Rudra Saraswat
  • 71
  • 1
  • 13
Tuna Karakasoglu
  • 1,262
  • 9
  • 28
  • Your solution worked well too, as i found some other solution. – sarkolata Jul 25 '12 at 17:52
  • I think this the best solution. – Code Droid Jul 25 '12 at 21:17
  • 2
    what if the user wants to accomplish something that uses connection to internet ? applying the above will make the handler and the runnable run on the UI thread, which prevents doing any network things. You need to implement thread there. – tony9099 Sep 23 '13 at 19:23
  • This is clever and I've used it in one part of my program and it works fine. But then I tried to use is in a service-like part of my program that does not have any UI, and that results in "java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()", which is fair enough. So this is a neat way to do timer-like processing, but just not in parts of the app that don't have a UI. – RenniePet Sep 06 '14 at 08:15
  • Even though this works, keep in mind that the Handler class schedules events on the thread in which had been called, even if it is the MainThread (https://stackoverflow.com/questions/31761351/difference-between-thread-and-handler) – Alessandro Muzzi Jun 15 '22 at 14:07
3

Use a CountDownTimer. The way it works is it will call a method on each tick of the timer, and another method when the timer ends. At which point you can restart if needed. Also I think you should probably be kicking off AsyncTask rather than threads. Please don't try to manage your own threads in Android. Try as below. Its runs like a clock.

 CountDownTimer myCountdownTimer =    new CountDownTimer(30000, 1000) {

 public void onTick(long millisUntilFinished) {
     mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
     // Kick off your AsyncTask here.
 }

 public void onFinish() {
     mTextField.setText("done!");
     // the 30 seconds is up now so do make any checks you need here.
 }
 }.start();
Code Droid
  • 10,344
  • 17
  • 72
  • 112
  • This does not repeatly does the thing. It did once then stopped! – sarkolata Jul 25 '12 at 13:13
  • Yes it does not run indefinitely. If you want to run it indefinitely you could consider a background service. On the other hand there is nothing to prevent you from restarting the countdown timer if conditions are right, or from setting a longer duration. – Code Droid Jul 25 '12 at 21:13
1

I would think to use AlarmManager http://developer.android.com/reference/android/app/AlarmManager.html

If checkbox is on call method where

AlarmManager alarmManager = (AlarmManager)SecureDocApplication.getContext()
    .getSystemService(Context.ALARM_SERVICE);
PendingIntent myService = PendingIntent.getService(context, 0, 
                new Intent(context, MyService.class), 0);

long triggerAtTime = 1000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, 5000 /* 5 sec*/, 
                myService);

If checkbox is off cancel alarm manager

alarmManager.cancel(myService);
Maxim
  • 4,152
  • 8
  • 50
  • 77
  • 1
    Have a class member variable which is instance of alarm manager. When checkbox is on call a method with that code. when off call method to shut down alarm manager. It it's going to happen when user browses through activities, then in inherited Application class. If user can exit app and that still need to be running then in the service. – Maxim Jul 25 '12 at 15:27
1

Thanks to everyone, I fixed this issue with using Timer.

timer = new Timer();
timer.scheduleAtFixedRate(
    new java.util.TimerTask() {
        @Override
        public void run() {
            for (int i = 0; i < server_amount; i++) {

                servers[i] = "Updating...";
                handler.sendEmptyMessage(0);
                new MyThread(i).start();
            }
        }
    },
2000, 5000);
MHSaffari
  • 858
  • 1
  • 16
  • 39
sarkolata
  • 370
  • 2
  • 7
  • 17
1

"[ScheduledThreadPoolExecutor] class is preferable to Timer when multiple worker threads are needed, or when the additional flexibility or capabilities of ThreadPoolExecutor (which this class extends) are required."

per...

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

It's not much more than the handler, but has the option of running exactly every so often (vice a delay after each computation completion).

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


...


final int THREAD_POOL_SIZE = 10;
final int START_DELAY = 0;
final int TIME_PERIOD = 5;
final TimeUnit TIME_UNIT = TimeUnit.SECONDS;

ScheduledThreadPoolExecutor pool;

Runnable myPeriodicThread = new Runnable() {
    @Override
    public void run() {
        refreshAllServers();
    }
};


public void startTimer(){

    pool.scheduleAtFixedRate(myPeriodicThread,
            START_DELAY,
            TIME_PERIOD,
            TIME_UNIT);

}

public void stopTimer(){

    pool.shutdownNow();

}
cloudsurfin
  • 2,467
  • 2
  • 25
  • 29