3

I've been very confused about this recently and can't find an answer anywhere.

When programming for android, I want to update a textview every 10 seconds, but how would I go about that? I've seen some samples use "Run()" and "Update()", but that doesn't seem to help when I try it, any ideas?

Right now I have:


public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.slideshow);

  CONST_TIME = (int) System.currentTimeMillis();

  Resources res = getResources();        
  myString = res.getStringArray(R.array.myArray);
}

public void checkTime(View V){
 TextView text = (TextView) findViewById(R.id.fadequote);
 CUR_TIME = (int) System.currentTimeMillis();
 text.setText(""+(int) (CUR_TIME-CONST_TIME));//Debugs how much time has gone by

 if(CUR_TIME-CONST_TIME>10000){
  getNextQuote(null); //A function that gets a random quote
  CONST_TIME = CUR_TIME;
 }
}

I guess what I'm REALLY asking is how do I make checkTime() repeat it-self endlessly until onPause() is called?

rds
  • 26,253
  • 19
  • 107
  • 134
QQWW1
  • 139
  • 2
  • 3
  • 7

5 Answers5

15

Rather than fuss with a background thread and then runOnUiThread(), use postDelayed(), available on any View, to schedule a Runnable. That Runnable can update your TextView and then schedule itself for the next pass. Using a background thread for the purposes of watching time tick by is a waste.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • How do you use this mechanism when updating a listview item? given that a view might be reused, in which case the previously scheduled runnable needs to be removed. how do you remove a posted runnable? – 500865 Jun 18 '13 at 03:20
  • 1
    @500865: "how do you remove a posted runnable" -- call `removeCallbacks()`. – CommonsWare Jun 18 '13 at 10:33
  • Thanks @CommonsWare. I never noticed that method in the View class. That should work. – 500865 Jun 18 '13 at 14:51
  • I know this is an old post, but I had to upvote it and comment because this is simple genius. I have recycler view whose item is a bit complex and it also has a textview which shows ticking time. Now to update each textview you cannot simply call any notify method. By this way only the textview is updated. Brilliant @CommonsWare thanks – Hardik4560 Apr 12 '16 at 11:29
  • I think we should create a separate handler and use WeakReference to a view to avoid memory leaks, what say? :) – Sarthak Mittal Feb 16 '18 at 12:56
  • @SarthakMittal: That is more complex than what I described, and I do not see how it adds any value. A `View` is not going to be leaked, unless you do something bad in your own code, such as put the `View` in a `static` field. – CommonsWare Feb 16 '18 at 13:23
  • @CommonsWare Umm, won't we be doing some view operations inside the run method? and won't that particular view leak context? – Sarthak Mittal Feb 16 '18 at 13:46
  • 1
    @SarthakMittal: Call `removeCallbacks()` when you no longer need the periodic work, or by `onDestroy()`. Until then, nothing gets leaked, because the `View` and its `Activity` still exist. – CommonsWare Feb 16 '18 at 13:55
  • @CommonsWare yes that's true! :) – Sarthak Mittal Feb 16 '18 at 14:41
11

What about using a timer?

private Timer timer = new Timer();
private TimerTask timerTask;
timerTask = new TimerTask() {
 @Override
 public void run() {
    //refresh your textview
 }
};
timer.schedule(timerTask, 0, 10000);

Cancel it via timer.cancel(). In your run() method you could use runOnUiThread();

UPDATE:

I have a livescoring app, which uses this Timer to update it every 30 sec. It looks like this:

private Timer timer;
private TimerTask timerTask;

public void onPause(){
    super.onPause();
    timer.cancel();
}

public void onResume(){
    super.onResume();
    try {
       timer = new Timer();
       timerTask = new TimerTask() {
          @Override
          public void run() {
         //Download file here and refresh
          }
       };
    timer.schedule(timerTask, 30000, 30000);
    } catch (IllegalStateException e){
       android.util.Log.i("Damn", "resume error");
    }
}
Rainer
  • 598
  • 1
  • 4
  • 16
  • Where do I put "Timertask = new TimerTask(){...}; timer.schedule(tiemrTask,0,10000);" ? Just under my class or do I need to put it under onResume();? Because I get errors if I put it in my class. – QQWW1 Jan 23 '11 at 22:23
  • So, I did that exactly (except instead of "//Download file here and refresh" i did "getNextQuote(null)" which will randomly find a quote from an array and refresh the textview with the new quote, but it will only do that once, not continuously. I set Timertask to 10 if that makes any sort of diffrence. Also no errors in LogCat – QQWW1 Jan 23 '11 at 23:04
  • Actually, I am mistaken, I put "android.util.Log.i("Success","getNextQuote returned");" after getNextQuote(null); and it comes up every 10 seconds!.. so mostly likely a mistake in the function itself.. thanks! – QQWW1 Jan 23 '11 at 23:10
  • 1
    You're welcome. I'm glad I could help you. To update the TextView you might then use something like runOnUiThread if you're expecting an error like: "Only the original thread that created a view hierarchy can touch its views". Good luck! – Rainer Jan 23 '11 at 23:17
8

I agree with Wired00's answer but please follow this order:

        //update current time view after every 1 seconds
        final Handler handler=new Handler();

        final Runnable updateTask=new Runnable() {
            @Override
            public void run() {
                updateCurrentTime();
                handler.postDelayed(this,1000);
            }
        };

        handler.postDelayed(updateTask,1000);
James Goodwin
  • 7,360
  • 5
  • 29
  • 41
Dhwaneel
  • 541
  • 5
  • 8
  • what is that post delayed multiple call by 1000 means? why dont just 1 postDelayed only? and if i'm not mistaken Handler is now deprecated right? any other alternatives? – gumuruh Dec 30 '21 at 09:41
5

incase it helps someone here is an example code using postDelayed()

...

private Handler mHandler = new Handler();

...

// call updateTask after 10seconds
mHandler.postDelayed(updateTask, 10000);

...

private Runnable updateTask = new Runnable () {
    public void run() {
        Log.d(getString(R.string.app_name) + " ChatList.updateTask()",
                "updateTask run!");

                    // run any code here...         

                    // queue the task to run again in 15 seconds...
                    mHandler.postDelayed(updateTask, 15000);


    }
};
wired00
  • 13,930
  • 7
  • 70
  • 73
0

Use a thread. See Painless Threading.

poke
  • 369,085
  • 72
  • 557
  • 602