0

I wanted to create countdown as soon as the user sees an activity. However, there does not seem to be an appropriate callback for that. Neither onResume nor onWindowFocusChanged seem to be the correct callbacks, because the whole code is executed before the user even see anything. As a result I end up with "Go!" on the screen right from the start.

In a nutshell: Do you have any idea how to implement a countdown without any user interaction as soon as the activity is visible to the user?

EDIT:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.concurrent.TimeUnit;
import android.widget.TextView;

public class ChallengeModeTutorial extends AppCompatActivity {

    private void delayOneSec()
    {
        try
        {
            TimeUnit.SECONDS.sleep(2);
        }
        catch (InterruptedException e)
        {
            assert true;
        }
    }

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

    @Override
    public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);
        TextView readySteadyGo = (TextView) findViewById(R.id.challengeModeTutorialReadySteadyGoTextView);
        // TextView tutorialText = (TextView) findViewById(R.id.challengeModeTutorialTextTextView);
        TextView timeUntilStart = (TextView) findViewById(R.id.challengeModeTutorialReadyTimeTextView);

        readySteadyGo.setText("");
        timeUntilStart.setText("5");
        delayOneSec();
        timeUntilStart.setText("4");
        delayOneSec();
        timeUntilStart.setText("3");
        delayOneSec();
        readySteadyGo.setText("Ready!");
        timeUntilStart.setText("2");
        delayOneSec();
        readySteadyGo.setText("Steady!");
        timeUntilStart.setText("1");
        delayOneSec();
        readySteadyGo.setText("");
        readySteadyGo.setText("Go!");
    }
}
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Alex
  • 751
  • 1
  • 6
  • 34
  • 1
    Have you tried `onStart`? – Suleyman May 27 '18 at 20:21
  • Yes, that one does not work either, but that is clear as all in onStart is done before the user sees anything. – Alex May 27 '18 at 20:24
  • 1
    "because the whole code is executed before the user even see anything" -- perhaps there is an issue with your code, rather than when the code is being executed. – CommonsWare May 27 '18 at 20:25
  • Try posting a runnable on root of the layout? It should be executed after layout/draw phase. – Pawel May 27 '18 at 20:26
  • Actually, that's not true, `onStart` is called once the Activity becomes visible. – Suleyman May 27 '18 at 20:27
  • Are you running sleep on UI thread? – Pawel May 27 '18 at 20:30
  • when another activity start, normally the previous activity will stop, so have you tried on onStop? when parent activity stop send something to the new starting activity and intercept it in on start, then from on start execute your countdown. – Daiwik Dan May 27 '18 at 20:35
  • @Pawel I'm running sleep in the UI thread. But why is that a problem if `onStart` and `onResume` are executed only after the activity is visible to the user? – Alex May 27 '18 at 20:35

4 Answers4

2

The problem is that you're blocking the UI thread. When you call setText(String) it doesn't immediately gets drawn. The TextView gets invalidated and it will be draw on the next draw phase. But if you block the thread, this will never happen. You have to use a postDelayed() to execute the next setText(String) a second later.

Budius
  • 39,391
  • 16
  • 102
  • 144
0

I'm not sure if this works, but you could try using a ViewTreeObserver in onCreate. It gets called once the layout is drawn. (Replace LinearLayout with whatever Layout your "activity_challenge_mode_tutorial" actually is.)

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

    final LinearLayout layout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID);
    ViewTreeObserver vto = layout.getViewTreeObserver(); 
    vto.addOnGlobalLayoutListener (new OnGlobalLayoutListener() { 
        @Override 
        public void onGlobalLayout() {
            // Remove listener to prevent repeat calls.
            layout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 

            // Start countdown here.

        } 
    });
}

Code is taken from this answer: https://stackoverflow.com/a/7735122/8118328

user8118328
  • 653
  • 1
  • 7
  • 10
0

You can start your countdown, inside of your onStart method, which you need to overwrite.

The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). During this time the user can see the activity on-screen, though it may not be in the foreground and interacting with the user.

From:
https://developer.android.com/reference/android/app/Activity

 @Override
protected void onStart() {
    super.onStart();
}
Christopher
  • 59
  • 10
0

I finally got it to work like this:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class ChallengeModeTutorial extends AppCompatActivity {

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

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

        final TextView readySteadyGo = (TextView) findViewById(R.id.challengeModeTutorialReadySteadyGoTextView);
        final TextView timeUntilStart = (TextView) findViewById(R.id.challengeModeTutorialReadyTimeTextView);

        readySteadyGo.setText("");

        Thread t=new Thread(){

            @Override
            public void run(){

                while(continueThread){

                    try {
                        Thread.sleep(1000);

                        runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                if(currentCount > 0)
                                {
                                    timeUntilStart.setText(String.valueOf(currentCount));
                                }
                                else
                                {
                                    timeUntilStart.setText("Go!");
                                }
                                switch (currentCount)
                                {
                                    case 2: readySteadyGo.setText("Ready!"); break;
                                    case 1: readySteadyGo.setText("Steady!"); break;
                                    default: readySteadyGo.setText(""); break;
                                }
                                currentCount--;
                                if (currentCount == 0)
                                {
                                    continueThread = false;
                                }
                            }
                        });

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        };

        t.start();
    }

    private boolean continueThread = true;
    private int currentCount = 5;
}
Alex
  • 751
  • 1
  • 6
  • 34