Search code examples
androidandroid-activitytextviewandroid-handler

Android Handler updates TextView only with last setText()


The following code is from Head First Android. It is for a stopwatch app.

I have a few questions in the following code:

  1. The code runs like -> OnCreate -> runTimer() (skips handler.post()) -> OnStart -> onResume -> Comes back to handler.post().

Why does it skip hander.post() in the first place?

  1. I have two textView.setText(). But the first one doesn't work. It's always the last one. I put the second one just to see what the code does after postDelay() method.

Why doesn't the first one work? I am expecting the text to jump back and forth from "hello" to "hh:mm:ss".

  1. So what exactly happens during the 1-second delay after postdelay() is executed.

Does the code starts running normally and when its 1 second the postDelay() is called?

  1. why is this used in postDealy(this, 100). shouldn't it be this.run()?

    public class MainActivity extends AppCompatActivity {       
        private boolean running = false;
        private int counter = 0;
        private Handler handler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            runTimer();
        }
    
        public void onClickStart(View view){
            running = true;
        }
    
        public void runTimer(){
            final TextView textView = findViewById(R.id.timer);
    
            handler.post(new Runnable() {
    
                @Override
                public void run() {
                    int hours = counter/3600;
                    int minutes = (counter%3600)/60;
                    int secs = counter%60;
    
                    String time = String.format("%d:%02d:%02d", hours, minutes, secs);
                    textView.setText(time); // Doesn't set it to this - see last line 
    
                    if(running){
                        counter++;
                    }
                    handler.postDelayed(this,1000); // what does happens between next one second 
                    textView.setText("hell0"); // Always set it to this 
                }
    
            });
        }
    

Solution

  • Why does it skip hander.post() in the first place?

    It is not skipped, it will be executed after onResume() returns. All the Runnables, queued though a Handler associated with the main thread, start their execution only after onResume() returns.

    Why doesn't the first one work?

    It does work. You just can't visually see it because the two method calls, textView.setText(), are invoked "almost" at the same time.

    The following sequence of calls happen at each run():

    • textView.setText(time),
    • the same Runnable is posted to the queue with handler.postDelayed(this,1000). Immediately after that
    • textView.setText("hell0") is called

    Why doesn't the first one work? I am expecting the text to jump back and forth from "hello" to "hh:mm:ss".

    You should implement an extra logic to switch between time and "hell0" at each run() execution.

    E.g. create a boolean flag in the Activity and set either time or "hell0" depending on the flag value (don't forget to change the flag value at each run() execution).

    why is this used in postDelay(this, 100). shouldn't it be this.run()?

    No, this.run() is executed synchronously (and immediately) and is of type void. The code won't compile as postDelay() expects the Runnable type, not void.