skip to Main Content

My OnStart() method should not get called because my onCreate() method will run infinitely. When OnCreate method runs, the runTimer() method gets called. This runTimer method will run infinitely because of handler.postDelayed. How is it that Android Studio is able to finish the infinite loop of the runTimer() method and then call OnStart() method?

    // MY STOPWATCH APP        
    


    public class MainActivity extends AppCompatActivity {
    private int seconds = 0;
    private boolean running;
    private boolean wasRunning;

    @Override
    // ON RUNNING MY APP FOR THE FIRST TIME THIS METHOD WILL GET CALLED FIRST.
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState != null) {
            seconds = savedInstanceState.getInt("seconds");
            running = savedInstanceState.getBoolean("running");
            wasRunning = savedInstanceState.getBoolean("wasRunning");
        }
        
        runTimer();
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putInt("seconds", seconds);
        savedInstanceState.putBoolean("running", running);
        savedInstanceState.putBoolean("wasRunning", wasRunning);
    }

    @Override
    protected void onStop() {
        super.onStop();
        wasRunning = running;
        running = false;
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (wasRunning) {
            running = true;
        }
    }

    //Start the stopwatch running when the Start button is clicked.
    public void onClickStart(View view) {
        running = true;
    }

    //Stop the stopwatch running when the Stop button is clicked.
    public void onClickStop(View view) {
        running = false;
    }

    //Reset the stopwatch when the Reset button is clicked.
    public void onClickReset(View view) {
        running = false;
        seconds = 0;
    }

    //Sets the number of seconds on the timer.
    private void runTimer() {
        final TextView timeView = (TextView)findViewById(R.id.tv_time_view);
        final Handler handler = new Handler();
        handler.post(new Runnable() {
            @Override
            public void run() {
                int hours = seconds/3600;
                int minutes = (seconds%3600)/60;
                int secs = seconds%60;
                String time = String.format(Locale.getDefault(),
                        "%d:%02d:%02d", hours, minutes, secs);
                timeView.setText(time);
                if (running) {
                    seconds++;
                }
                handler.postDelayed(this, 1000);
            }
        });
    }
}

2

Answers


  1. Why do you think that runTimer() will run indefinitely?

    handler.post() and handler.postDelayed() add an object (your new Runnable() {}) to the message queue so the objects run() method can be executed some time later.

    handler.post() returns after adding the object to the message queue and therefore the runTimer() and onCreate() methods finish normally.


    Why "Message Queue"? Because the documentation says so:

    https://developer.android.com/reference/android/os/Handler:

    A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue

    https://developer.android.com/reference/android/os/Handler#post(java.lang.Runnable):

    Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.

    https://developer.android.com/reference/android/os/Handler#postDelayed(java.lang.Runnable,%20long):

    Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses.

    The whole point of using a Handler is to allow the Runnables that are post()ed to execute at some later point in time so that the current thread can continue its work.

    If the handler would execute the code within the Runnable directly (and blocking) then you could have written your code as new Runnable() { /*...*/ }.run();

    Login or Signup to reply.
  2. The handler.post will execute the Runnable on the handler thread, so runTimer() will exist after the call to handler.post()

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search