376

Can someone give a simple example of updating a textfield every second or so?

I want to make a flying ball and need to calculate/update the ball coordinates every second, that's why I need some sort of a timer.

I don't get anything from here.

Awais Aslam
  • 75
  • 1
  • 1
  • 9
SERG
  • 3,907
  • 8
  • 44
  • 89

24 Answers24

498

ok since this isn't cleared up yet there are 3 simple ways to handle this. Below is an example showing all 3 and at the bottom is an example showing just the method I believe is preferable. Also remember to clean up your tasks in onPause, saving state if necessary.


import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Handler.Callback;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class main extends Activity {
    TextView text, text2, text3;
    long starttime = 0;
    //this  posts a message to the main thread from our timertask
    //and updates the textfield
   final Handler h = new Handler(new Callback() {

        @Override
        public boolean handleMessage(Message msg) {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text.setText(String.format("%d:%02d", minutes, seconds));
            return false;
        }
    });
   //runs without timer be reposting self
   Handler h2 = new Handler();
   Runnable run = new Runnable() {

        @Override
        public void run() {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text3.setText(String.format("%d:%02d", minutes, seconds));

           h2.postDelayed(this, 500);
        }
    };

   //tells handler to send a message
   class firstTask extends TimerTask {

        @Override
        public void run() {
            h.sendEmptyMessage(0);
        }
   };

   //tells activity to run on ui thread
   class secondTask extends TimerTask {

        @Override
        public void run() {
            main.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                   long millis = System.currentTimeMillis() - starttime;
                   int seconds = (int) (millis / 1000);
                   int minutes = seconds / 60;
                   seconds     = seconds % 60;

                   text2.setText(String.format("%d:%02d", minutes, seconds));
                }
            });
        }
   };


   Timer timer = new Timer();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        text = (TextView)findViewById(R.id.text);
        text2 = (TextView)findViewById(R.id.text2);
        text3 = (TextView)findViewById(R.id.text3);

        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button)v;
                if(b.getText().equals("stop")){
                    timer.cancel();
                    timer.purge();
                    h2.removeCallbacks(run);
                    b.setText("start");
                }else{
                    starttime = System.currentTimeMillis();
                    timer = new Timer();
                    timer.schedule(new firstTask(), 0,500);
                    timer.schedule(new secondTask(),  0,500);
                    h2.postDelayed(run, 0);
                    b.setText("stop");
                }
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        timer.cancel();
        timer.purge();
        h2.removeCallbacks(run);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }
}


the main thing to remember is that the UI can only be modified from the main ui thread so use a handler or activity.runOnUIThread(Runnable r);

Here is what I consider to be the preferred method.


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class TestActivity extends Activity {

    TextView timerTextView;
    long startTime = 0;

    //runs without a timer by reposting this handler at the end of the runnable
    Handler timerHandler = new Handler();
    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            long millis = System.currentTimeMillis() - startTime;
            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds = seconds % 60;

            timerTextView.setText(String.format("%d:%02d", minutes, seconds));

            timerHandler.postDelayed(this, 500);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        timerTextView = (TextView) findViewById(R.id.timerTextView);

        Button b = (Button) findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button) v;
                if (b.getText().equals("stop")) {
                    timerHandler.removeCallbacks(timerRunnable);
                    b.setText("start");
                } else {
                    startTime = System.currentTimeMillis();
                    timerHandler.postDelayed(timerRunnable, 0);
                    b.setText("stop");
                }
            }
        });
    }

  @Override
    public void onPause() {
        super.onPause();
        timerHandler.removeCallbacks(timerRunnable);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }

}


Dave.B
  • 6,632
  • 1
  • 19
  • 20
  • so you can see that each of the demonstrated methods acts the same – Dave.B Apr 05 '12 at 16:31
  • 1
    @Dave.B, thanks for the great example. Are there any advantages/disadvantages to using one method vs the others you have outlined? – Gautam Sep 16 '12 at 04:45
  • 2
    @Gautam I believe the all the methods above perform about the same. I personally prefer the handler method described above with the run Runnable and h2 Handler as it is the one prescribed by the android developer site and in my opinion also the most elegant. – Dave.B Sep 17 '12 at 19:23
  • Handler code is good. Code that is run in a Timer may have difficulties with UI updates. – DragonLord Jun 27 '13 at 02:55
  • Just to add for future people browsing SO. There is AlarmManager way too – Snake Jul 17 '13 at 19:31
  • 8
    It would be nice to have your preferred method separated from the rest of the code. Like you could have one example showing your preferred way and another showing the alternatives. Having all three methods together makes it harder to understand what's going on (especialy for an android newbie like me). Probably asking too much though :) – Jesse Aldridge Oct 10 '13 at 22:30
  • 5
    @JesseAldridge Good idea. I went ahead and added code with the preferred method only. – Dave.B Oct 17 '13 at 17:29
  • Shouldn't you remove the callbacks in onPause() ? As it is, the callbacks will just continue in the background even if you leave the app, right? – Divisible by Zero Nov 28 '13 at 17:17
  • @Dave.B Why you won't just MainActivity.this.timerRunnable.run(); at the start ? But instead you schedule it for 0 ms ? – Paweł Brewczynski Dec 04 '13 at 23:41
  • 1
    @bluesm I honestly just didn't think about it but yes that would work fine. – Dave.B Dec 05 '13 at 18:41
  • @Snake - AlarmManager has a rather different use: to wake up your app in the future, if it has been paused. – ToolmakerSteve Sep 12 '14 at 15:57
  • Slightly simpler example http://www.mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler/ but uses the same theory. – Robbie Mar 03 '15 at 04:56
  • Won't the preferred method fail to stop the recurrence if the Runnable - possibly doing a lengthy request - is running at the time onPause occurs? Or is that impossible, running on UI Thread? – kaay Jun 14 '16 at 09:55
  • What happens if removeCallbacks() is called right during the execution of the runnable? (meaning before postDelayed() is called again). Am I correct to assume it would not stop the timer since it would be restarted right after? In this case it would be better to use a Boolean timerEnabled and call postDelayed() only if true. – FlorianB Sep 06 '16 at 21:13
  • 3
    note to people inventing Java / Android: why do you make it so hard to do simple things like a timer. You would think you could have something like Timer().schedule( .. code block .. , milliseconds); and be done ... – quemeful Oct 13 '16 at 14:38
  • Should have given only one example. – Muddassir Ahmed May 05 '17 at 18:50
  • I was waiting for this so long. Best implementation for the timer problems. – Dinith Rukshan Kumara Jul 16 '20 at 19:42
99

It is simple! You create new timer.

Timer timer = new Timer();

Then you extend the timer task

class UpdateBallTask extends TimerTask {
   Ball myBall;

   public void run() {
       //calculate the new position of myBall
   }
}

And then add the new task to the Timer with some update interval

final int FPS = 40;
TimerTask updateBall = new UpdateBallTask();
timer.scheduleAtFixedRate(updateBall, 0, 1000/FPS);

Disclaimer: This is not the ideal solution. This is solution using the Timer class (as asked by OP). In Android SDK, it is recommended to use the Handler class (there is example in the accepted answer).

Kiril Kirilov
  • 11,167
  • 5
  • 49
  • 74
72

If you also need to run your code on UI thread (and not on timer thread), take a look on the blog: http://steve.odyfamily.com/?p=12

public class myActivity extends Activity {
private Timer myTimer;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    myTimer = new Timer();
    myTimer.schedule(new TimerTask() {          
        @Override
        public void run() {
            TimerMethod();
        }

    }, 0, 1000);
}

private void TimerMethod()
{
    //This method is called directly by the timer
    //and runs in the same thread as the timer.

    //We call the method that will work with the UI
    //through the runOnUiThread method.
    this.runOnUiThread(Timer_Tick);
}


private Runnable Timer_Tick = new Runnable() {
    public void run() {

    //This method runs in the same thread as the UI.               

    //Do something to the UI thread here

    }
};
}
Meir Gerenstadt
  • 3,573
  • 1
  • 23
  • 22
  • For the sake of completeness you could perhaps mention what to do to stop the timer, and maybe restart it. (I found the necessary info here: http://stackoverflow.com/questions/11550561/pause-the-timer-and-then-continue-it ) – RenniePet Apr 25 '14 at 14:39
  • 4
    Is there any reason you cant just call runOnUIThread directly from TimerTask run method? Seems to work fine and removes another level of nesting. – RichieHH Jul 19 '14 at 22:06
  • Sure, it is only a didactic method to understand all the steps. I suggest this standard to have a readable code. – Meir Gerenstadt Jul 20 '14 at 11:58
53

If one just want to schedule a countdown until a time in the future with regular notifications on intervals along the way, you can use the CountDownTimer class that is available since API level 1.

new CountDownTimer(30000, 1000) {
    public void onTick(long millisUntilFinished) {
        editText.setText("Seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        editText.setText("Done");
    }
}.start();
Ahmed Hegazy
  • 12,395
  • 5
  • 41
  • 64
  • 3
    CountDownTimer only makes sense if you know that you want it to go away after several executions. This is not a typical, nor particularly flexible, approach. More common is the timer that repeats forever (which you cancel when no longer needed), or the handler that runs once, and then starts itself again if will be needed again. See other answers. – ToolmakerSteve Sep 12 '14 at 15:42
  • 1
    You are totally right. From the class name it provides one time count down timer ticking until finish and of course it uses Handler in its implementation. – Ahmed Hegazy Sep 13 '14 at 13:51
  • How to show milliseconds also? In the format `SS:MiMi`? Thanks – Ruchir Baronia Dec 07 '15 at 12:38
  • This answer is exactly what i looking for – Avinash Jun 30 '21 at 05:45
31

This is some simple code for a timer:

Timer timer = new Timer();
TimerTask t = new TimerTask() {       
    @Override
    public void run() {

        System.out.println("1");
    }
};
timer.scheduleAtFixedRate(t,1000,1000);
Pochmurnik
  • 780
  • 6
  • 18
  • 35
Jevgenij Kononov
  • 1,210
  • 16
  • 11
14

I think you can do it in Rx way like:

 timerSubscribe = Observable.interval(1, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                      //TODO do your stuff
                }
            });

And cancel this like:

timerSubscribe.unsubscribe();

Rx Timer http://reactivex.io/documentation/operators/timer.html

Will
  • 151
  • 1
  • 6
13

I'm surprised that there is no answer that would mention solution with RxJava2. It is really simple and provides an easy way to setup timer in Android.

First you need to setup Gradle dependency, if you didn't do so already:

implementation "io.reactivex.rxjava2:rxjava:2.x.y"

(replace x and y with current version number)

Since we have just a simple, NON-REPEATING TASK, we can use Completable object:

Completable.timer(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(() -> {
            // Timer finished, do something...
        });

For REPEATING TASK, you can use Observable in a similar way:

Observable.interval(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(tick -> {
            // called every 2 seconds, do something...
        }, throwable -> {
            // handle error
        });

Schedulers.computation() ensures that our timer is running on background thread and .observeOn(AndroidSchedulers.mainThread()) means code we run after timer finishes will be done on main thread.

To avoid unwanted memory leaks, you should ensure to unsubscribe when Activity/Fragment is destroyed.

Micer
  • 8,731
  • 3
  • 79
  • 73
  • 5
    This is the cleanest approach! – Constantin May 15 '18 at 18:43
  • how does one cancel these ? i.e. when the user presses the [STOP] button on the UI and the Completable is canceled before executing. – Someone Somewhere Jun 11 '19 at 15:40
  • @SomeoneSomewhere Just save the `Subscription` returned by `.subscribe()` method in the variable and then call `subscription.unsubscribe()` when you want to stop the timer. – Micer Jun 19 '19 at 07:24
12

Because this question is still attracting a lot of users from google search(about Android timer) I would like to insert my two coins.

First of all, the Timer class will be deprecated in Java 9 (read the accepted answer).

The official suggested way is to use ScheduledThreadPoolExecutor which is more effective and features-rich that can additionally schedule commands to run after a given delay, or to execute periodically. Plus,it gives additional flexibility and capabilities of ThreadPoolExecutor.

Here is an example of using plain functionalities.

  1. Create executor service:

    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
    
  2. Just schedule you runnable:

    final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
    
  3. You can now use future to cancel the task or check if it is done for example:

    future.isDone();
    

Hope you will find this useful for creating a tasks in Android.

Complete example:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
    // Do something which will save world.
}
Community
  • 1
  • 1
szholdiyarov
  • 385
  • 2
  • 12
8

for whom wants to do this in kotlin:

val timer = fixedRateTimer(period = 1000L) {
            val currentTime: Date = Calendar.getInstance().time
            runOnUiThread {
                tvFOO.text = currentTime.toString()
            }
        }

for stopping the timer you can use this:

timer.cancel()

this function has many other options, give it a try

Amir
  • 318
  • 1
  • 5
  • 11
3
import kotlin.concurrent.fixedRateTimer

val timer = fixedRateTimer("Tag", false, 1000, 2500) { /* Your code here */ }

Pretty simple with Kotlin

Kevin
  • 1,405
  • 15
  • 16
2

You want your UI updates to happen in the already-existent UI thread.

The best way is to use a Handler that uses postDelayed to run a Runnable after a delay (each run schedules the next); clear the callback with removeCallbacks.

You're already looking in the right place, so look at it again, perhaps clarify why that code sample isn't what you want. (See also the identical article at Updating the UI from a Timer).

Risinek
  • 390
  • 2
  • 16
Liudvikas Bukys
  • 5,790
  • 3
  • 25
  • 36
1

He're is simplier solution, works fine in my app.

  public class MyActivity extends Acitivity {

    TextView myTextView;
    boolean someCondition=true;

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

            myTextView = (TextView) findViewById(R.id.refreshing_field);

            //starting our task which update textview every 1000 ms
            new RefreshTask().execute();



        }

    //class which updates our textview every second

    class RefreshTask extends AsyncTask {

            @Override
            protected void onProgressUpdate(Object... values) {
                super.onProgressUpdate(values);
                String text = String.valueOf(System.currentTimeMillis());
                myTextView.setText(text);

            }

            @Override
            protected Object doInBackground(Object... params) {
                while(someCondition) {
                    try {
                        //sleep for 1s in background...
                        Thread.sleep(1000);
                        //and update textview in ui thread
                        publishProgress();
                    } catch (InterruptedException e) {
                        e.printStackTrace(); 

                };
                return null;
            }
        }
    }
Rodion Altshuler
  • 1,713
  • 1
  • 15
  • 31
1

You can also use an animator for it:

int secondsToRun = 999;

ValueAnimator timer = ValueAnimator.ofInt(secondsToRun);
timer.setDuration(secondsToRun * 1000).setInterpolator(new LinearInterpolator());
timer.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            int elapsedSeconds = (int) animation.getAnimatedValue();
            int minutes = elapsedSeconds / 60;
            int seconds = elapsedSeconds % 60;

            textView.setText(String.format("%d:%02d", minutes, seconds));
        }
    });
timer.start();
TpoM6oH
  • 8,385
  • 3
  • 40
  • 72
1

For those who can't rely on Chronometer, I made a utility class out of one of the suggestions:

public class TimerTextHelper implements Runnable {
   private final Handler handler = new Handler();
   private final TextView textView;
   private volatile long startTime;
   private volatile long elapsedTime;

   public TimerTextHelper(TextView textView) {
       this.textView = textView;
   }

   @Override
   public void run() {
       long millis = System.currentTimeMillis() - startTime;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds = seconds % 60;

       textView.setText(String.format("%d:%02d", minutes, seconds));

       if (elapsedTime == -1) {
           handler.postDelayed(this, 500);
       }
   }

   public void start() {
       this.startTime = System.currentTimeMillis();
       this.elapsedTime = -1;
       handler.post(this);
   }

   public void stop() {
       this.elapsedTime = System.currentTimeMillis() - startTime;
       handler.removeCallbacks(this);
   }

   public long getElapsedTime() {
       return elapsedTime;
   }
 }

to use..just do:

 TimerTextHelper timerTextHelper = new TimerTextHelper(textView);
 timerTextHelper.start();

.....

 timerTextHelper.stop();
 long elapsedTime = timerTextHelper.getElapsedTime();
Jon
  • 3,573
  • 2
  • 17
  • 24
Alécio Carvalho
  • 13,481
  • 5
  • 68
  • 74
1
enter code here
Thread th=new Thread(new Runnable() {
        @Override
        public void run() {
            try { for(int i=0;i<5;i++) {
                b1.setText(""+i);
                Thread.sleep(5000);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
       pp();
       
                        }
                    }
                });
            }} catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    th.start();
amra ram
  • 81
  • 1
  • 2
1

Here is the solution for this you need to add the following class in your code. And you can directly add a view to your XML file.

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class TimerTextView extends TextView {

    private static final int DEFAULT_INTERVAL = 1000;

    private Timer timer = new Timer();
    private long endTime = 0;
    private long interval = DEFAULT_INTERVAL;
    private boolean isCanceled = false;

    public TimerTextView(Context context) {
        super(context);
    }

    public TimerTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopTimer();
    }

    @Override protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (VISIBLE == visibility) {
            startTimer();
        } else {
            stopTimer();
        }
    }

    public void setInterval(long interval) {
        if (interval >= 0) {
            this.interval = interval;
            stopTimer();
            startTimer();
        }
    }

    public void setEndTime(long endTime) {
        if (endTime >= 0) {
            this.endTime = endTime;
            stopTimer();
            startTimer();
        }
    }

    private void startTimer() {
        if (endTime == 0) {
            return;
        }
        if (isCanceled) {
            timer = new Timer();
            isCanceled = false;
        }
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override public void run() {
                if (null == getHandler()) {
                    return;
                }
                getHandler().post(new Runnable() {
                    @Override public void run() {
                        setText(getDurationBreakdown(endTime - System.currentTimeMillis()));
                    }
                });
            }
        }, 0, interval);
    }

    private void stopTimer() {
        timer.cancel();
        isCanceled = true;
    }

    private String getDurationBreakdown(long diff) {
        long millis = diff;
        if (millis < 0) {
            return "00:00:00";
        }
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
        millis -= TimeUnit.HOURS.toMillis(hours);
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
        millis -= TimeUnit.MINUTES.toMillis(minutes);
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);


        return String.format(Locale.ENGLISH, "%02d:%02d:%02d", hours, minutes, seconds);
        //return "${getWithLeadZero(hours)}:${getWithLeadZero(minutes)}:${getWithLeadZero(seconds)}"
    }
}
Sahil Bansal
  • 609
  • 8
  • 6
0
void method(boolean u,int max)
{
    uu=u;
    maxi=max;
    if (uu==true)
    { 
        CountDownTimer uy = new CountDownTimer(maxi, 1000) 
  {
            public void onFinish()
            {
                text.setText("Finish"); 
            }

            @Override
            public void onTick(long l) {
                String currentTimeString=DateFormat.getTimeInstance().format(new Date());
                text.setText(currentTimeString);
            }
        }.start();
    }

    else{text.setText("Stop ");
}
WEFX
  • 8,298
  • 8
  • 66
  • 102
0

If anyone is interested, I started playing around with creating a standard object to run on an activities UI thread. Seems to work ok. Comments welcome. I'd love this to be available on the layout designer as a component to drag onto an Activity. Can't believe something like that doesn't already exist.

package com.example.util.timer;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;

public class ActivityTimer {

    private Activity m_Activity;
    private boolean m_Enabled;
    private Timer m_Timer;
    private long m_Delay;
    private long m_Period;
    private ActivityTimerListener m_Listener;
    private ActivityTimer _self;
    private boolean m_FireOnce;

    public ActivityTimer() {
        m_Delay = 0;
        m_Period = 100;
        m_Listener = null;
        m_FireOnce = false;
        _self = this;
    }

    public boolean isEnabled() {
        return m_Enabled;
    }

    public void setEnabled(boolean enabled) {
        if (m_Enabled == enabled)
            return;

        // Disable any existing timer before we enable a new one
        Disable();

        if (enabled) {
            Enable();
        }
    }

    private void Enable() {
        if (m_Enabled)
            return;

        m_Enabled = true;

        m_Timer = new Timer();
        if (m_FireOnce) {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay);
        } else {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay, m_Period);
        }
    }

    private void Disable() {
        if (!m_Enabled)
            return;

        m_Enabled = false;

        if (m_Timer == null)
            return;

        m_Timer.cancel();
        m_Timer.purge();
        m_Timer = null;
    }

    private void OnTick() {
        if (m_Activity != null && m_Listener != null) {
            m_Activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    m_Listener.OnTimerTick(m_Activity, _self);
                }
            });
        }
        if (m_FireOnce)
            Disable();
    }

    public long getDelay() {
        return m_Delay;
    }

    public void setDelay(long delay) {
        m_Delay = delay;
    }

    public long getPeriod() {
        return m_Period;
    }

    public void setPeriod(long period) {
        if (m_Period == period)
            return;
        m_Period = period;
    }

    public Activity getActivity() {
        return m_Activity;
    }

    public void setActivity(Activity activity) {
        if (m_Activity == activity)
            return;
        m_Activity = activity;
    }

    public ActivityTimerListener getActionListener() {
        return m_Listener;
    }

    public void setActionListener(ActivityTimerListener listener) {
        m_Listener = listener;
    }

    public void start() {
        if (m_Enabled)
            return;
        Enable();
    }

    public boolean isFireOnlyOnce() {
        return m_FireOnce;
    }

    public void setFireOnlyOnce(boolean fireOnce) {
        m_FireOnce = fireOnce;
    }
}

In the activity, I have this onStart:

@Override
protected void onStart() {
    super.onStart();

    m_Timer = new ActivityTimer();
    m_Timer.setFireOnlyOnce(true);
    m_Timer.setActivity(this);
    m_Timer.setActionListener(this);
    m_Timer.setDelay(3000);
    m_Timer.start();
}
James Barwick
  • 438
  • 3
  • 8
0

Here is a simple reliable way...

Put the following code in your Activity, and the tick() method will be called every second in the UI thread while your activity is in the "resumed" state. Of course, you can change the tick() method to do what you want, or to be called more or less frequently.

@Override
public void onPause() {
    _handler = null;
    super.onPause();
}

private Handler _handler;

@Override
public void onResume() {
    super.onResume();
    _handler = new Handler();
    Runnable r = new Runnable() {
        public void run() {
            if (_handler == _h0) {
                tick();
                _handler.postDelayed(this, 1000);
            }
        }

        private final Handler _h0 = _handler;
    };
    r.run();
}

private void tick() {
    System.out.println("Tick " + System.currentTimeMillis());
}

For those interested, the "_h0=_handler" code is necessary to avoid two timers running simultaneously if your activity is paused and resumed within the tick period.

Adam Gawne-Cain
  • 1,347
  • 14
  • 14
0
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 CheckBox optSingleShot;
 Button btnStart, btnCancel;
 TextView textCounter;

 Timer timer;
 MyTimerTask myTimerTask;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  optSingleShot = (CheckBox)findViewById(R.id.singleshot);
  btnStart = (Button)findViewById(R.id.start);
  btnCancel = (Button)findViewById(R.id.cancel);
  textCounter = (TextView)findViewById(R.id.counter);

  btnStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {

    if(timer != null){
     timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
     //singleshot delay 1000 ms
     timer.schedule(myTimerTask, 1000);
    }else{
     //delay 1000ms, repeat in 5000ms
     timer.schedule(myTimerTask, 1000, 5000);
    }
   }});

  btnCancel.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if (timer!=null){
     timer.cancel();
     timer = null;
    }
   }
  });

 }

 class MyTimerTask extends TimerTask {

  @Override
  public void run() {
   Calendar calendar = Calendar.getInstance();
   SimpleDateFormat simpleDateFormat = 
     new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
   final String strDate = simpleDateFormat.format(calendar.getTime());

   runOnUiThread(new Runnable(){

    @Override
    public void run() {
     textCounter.setText(strDate);
    }});
  }

 }

}

.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:autoLink="web"
    android:text="http://android-er.blogspot.com/"
    android:textStyle="bold" />
<CheckBox 
    android:id="@+id/singleshot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Single Shot"/>

Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
  • I see that you've added this several years after the original question & answers. Please add explanation of how this answer compares to other answers that were already there. Why did you add another - what benefit / when useful / what shortcoming did you see in other answers? – ToolmakerSteve Sep 12 '14 at 15:45
  • I just share a code which is doing same work with a different approach. But whenever you want to update any view's data. You must use handler for it. because many time i have notice that using a timertask to update a view doesn't work .. @Dave.B method is more correct to my knowledge. – Zar E Ahmer Sep 15 '14 at 06:58
0

If you have delta time already.

public class Timer {
    private float lastFrameChanged;
    private float frameDuration;
    private Runnable r;

    public Timer(float frameDuration, Runnable r) {
        this.frameDuration = frameDuration;
        this.lastFrameChanged = 0;
        this.r = r;
    }

    public void update(float dt) {
        lastFrameChanged += dt;

        if (lastFrameChanged > frameDuration) {
            lastFrameChanged = 0;
            r.run();
        }
    }
}
Matthew Beck
  • 339
  • 3
  • 10
0

You need to create a thread to handle the update loop and use it to update the textarea. The tricky part though is that only the main thread can actually modify the ui so the update loop thread needs to signal the main thread to do the update. This is done using a Handler.

Check out this link: http://developer.android.com/guide/topics/ui/dialogs.html# Click on the section titled "Example ProgressDialog with a second thread". It's an example of exactly what you need to do, except with a progress dialog instead of a textfield.

Nick
  • 8,181
  • 4
  • 38
  • 63
  • Don't do this. There is a simple timer class that does this all for you. And this question has nothing at all to do with progressdialogs, or dialogs at all. – Falmarri Jan 04 '11 at 20:04
  • Did you look at the section of the link I posted or did you just see the word dialog and assume? The code there is 100% relevant. Also FYI, if you use timer, you are still creating a thread to handle the update loop. You'll still need to use the Handler as described in the link I posted. – Nick Jan 04 '11 at 21:08
  • Unfortunately, the linked page no longer contains a section with the title mentioned. When linking to code, one should always include the key snippet directly within your answer. – ToolmakerSteve Sep 12 '14 at 16:20
0

I Abstract Timer away and made it a separate class:

Timer.java

import android.os.Handler;

public class Timer {

    IAction action;
    Handler timerHandler = new Handler();
    int delayMS = 1000;

    public Timer(IAction action, int delayMS) {
        this.action = action;
        this.delayMS = delayMS;
    }

    public Timer(IAction action) {
        this(action, 1000);
    }

    public Timer() {
        this(null);
    }

    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            if (action != null)
                action.Task();
            timerHandler.postDelayed(this, delayMS);
        }
    };

    public void start() {
        timerHandler.postDelayed(timerRunnable, 0);
    }

    public void stop() {
        timerHandler.removeCallbacks(timerRunnable);
    }
}

And Extract main action from Timer class out as

IAction.java

public interface IAction {
    void Task();
}

And I used it just like this:

MainActivity.java

public class MainActivity extends Activity implements IAction{
...
Timer timerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
        ...
        timerClass = new Timer(this,1000);
        timerClass.start();
        ...
}
...
int i = 1;
@Override
public void Task() {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            timer.setText(i + "");
            i++;
        }
    });
}
...
}

I Hope This Helps

Yashar Aliabbasi
  • 2,663
  • 1
  • 23
  • 35
0

I use this way:

String[] array={
       "man","for","think"
}; int j;

then below the onCreate

TextView t = findViewById(R.id.textView);

    new CountDownTimer(5000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {}

        @Override
        public void onFinish() {
            t.setText("I "+array[j] +" You");
            j++;
            if(j== array.length-1) j=0;
            start();
        }
    }.start();

it's easy way to solve this problem.

Mori
  • 2,653
  • 18
  • 24