16

I would like to start repeating two lines of code every 5 seconds when I press the button START and end it, when I press the button STOP. I was trynig with a TimerTask and Handles, but couldn't figure it out how.

public class MainActivity extends Activity {




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


           //final int i;
           final TextView textView = (TextView) findViewById(R.id.textView);
           final Button START_STOP = (Button) findViewById(R.id.START_STOP);
           final ImageView random_note = (ImageView) findViewById(R.id.random_note);
           final int min = 0;
           final int max = 2;
           final Integer[] image = { R.drawable.a0, R.drawable.a1,R.drawable.a2 };



        START_STOP.setTag(1);
        START_STOP.setText("START");


        START_STOP.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
            int status = (Integer) v.getTag();
            if (status ==1) {
                textView.setText("Hello");
                START_STOP.setText("STOP");
                v.setTag(0);

                final Random random = new Random();

                                //************************************************************
                // I would like to loop next 2 lines of code every 5 seconds.//

                                int i = random.nextInt(2 - 0 + 1) + 0;
                random_note.setImageResource(image[i]);

                //************************************************************
                    }

            else
            {
                textView.setText("Bye");
                START_STOP.setText("Let's PLAY!");
                v.setTag(1);
            }


            }
        });     

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


}
Dyna
  • 2,304
  • 1
  • 14
  • 25
Damijan
  • 183
  • 1
  • 2
  • 7
  • 1
    What did not work with the TimerTask? – FD_ Feb 12 '14 at 11:03
  • I don't know. When I tried to run it on the emulator, it crashed. But probabbly I did something wrong, since I am an Android (Java) beginner. – Damijan Feb 12 '14 at 11:17

4 Answers4

34

Using a CountDownTimer as in one of the other answers is one way to do it. Another would be to use a Handler and the postDelayed method:

private boolean started = false;
private Handler handler = new Handler();

private Runnable runnable = new Runnable() {        
    @Override
    public void run() {
        final Random random = new Random();
        int i = random.nextInt(2 - 0 + 1) + 0;
        random_note.setImageResource(image[i]);
        if(started) {
            start();
        }
    }
};

public void stop() {
    started = false;
    handler.removeCallbacks(runnable);
}

public void start() {
    started = true;
    handler.postDelayed(runnable, 2000);        
}

Here's an example using a Timer and a TimerTask:

private Timer timer;
private TimerTask timerTask = new TimerTask() {

    @Override
    public void run() {
        final Random random = new Random();
        int i = random.nextInt(2 - 0 + 1) + 0;
        random_note.setImageResource(image[i]);
    }
};

public void start() {
    if(timer != null) {
        return;
    }
    timer = new Timer();
    timer.scheduleAtFixedRate(timerTask, 0, 2000);
}

public void stop() {
    timer.cancel();
    timer = null;
}
britzl
  • 10,132
  • 7
  • 41
  • 38
  • 1
    I have always used a CountDownTimer in my apps, like to change the banners in an activity every 5 seconds. What's the best way to repeat some action every 5 seconds, the CountDownTimer or the Handler and postDelayed? – Giacomoni Feb 12 '14 at 11:21
  • Thanks. Where would you put that in my original code? – Damijan Feb 12 '14 at 11:57
  • 3
    Good question giacomoni! I had a look at the CountDownTimer and it uses a Handler internally: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.0_r1/android/os/CountDownTimer.java#109 so I guess they are more or less equivalent. The Timer uses a TimerThread with a queue of TimerTasks: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Timer.java#460 It's hard to say which one is better. I don't know enough about the differences between threads and handlers to give you a good enough answer. – britzl Feb 12 '14 at 14:28
  • 1
    @Damijan Put the start and stop methods somewhere in your activity. Call them from the onClick() method depending on button state. Put the TimerTask or the Runnable inside your activity as well as normal member variables of the Activity – britzl Feb 12 '14 at 14:31
14

You can use CountDownTimer as the following method:

private CountDownTimer timer;

timer = new CountDownTimer(5000, 20) {

    @Override
    public void onTick(long millisUntilFinished) {

    }

    @Override
    public void onFinish() {
        try{
            yourMethod();
        }catch(Exception e){
            Log.e("Error", "Error: " + e.toString());
        }
    }
}.start();

And then to call the timer again:

public void yourMethod(){
    //do what you want
    timer.start();
}

To cancel the timer, you can call timer.cancel();

Hope it helps!

Giacomoni
  • 1,468
  • 13
  • 18
  • hello sir, can the above code be used to refresh an activity until the user clicks back button...? –  Jan 06 '17 at 08:22
7

You can use RxJava2/RxAndroid2 and create an Observable that emits a message every second (or whatever you want), example with pseudo code:

Disposable timer = Observable.interval(1000L, TimeUnit.MILLISECONDS)
            .timeInterval()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<Timed<Long>>() {
                @Override
                public void accept(@NonNull Timed<Long> longTimed) throws Exception {               
                    //your code here.
                    Log.d(TAG, new DateTime());
                }
            });

When you want to stop it, you can simply call:

timer.dispose();

I find this code much more readable than the other options.

db80
  • 4,157
  • 1
  • 38
  • 38
0

I don't have much more to add, other than to mention the differences between using Handler, CountDownTimer, and regular Timer. As britzl mentioned, the CountDownTimer uses a Handler internally, so that is equivalent to using the handler directly. A handler is used for running Ui stuff, for very short periods of time. An example would be setText for a text view. For computationally intensive tasks, handlers may cause a lag. A timer also can only run short tasks, but it is not necessarily only for UI stuff. For more complicated tasks, a new Thread should be used.