1

I'm trying to develop a method that will loop through a String variable and change the background color based on each character, with a one second delay so each individual color can be observed by the user. I've looked into similar problems, and most of the answers recommend Handlers() or Timers(), as sleeping the UI thread is not recommended.

The issue I'm having is that both the Handler methods and the Timer methods each create Runnables or TimerTasks, and I can't send the int value of my loop iterator without declaring it a final variable, which prevents me from incrementing to the next letter of the String.

public void replayPattern(View view){
        int i=0;
        String temp;
        int delay = 1000;
        RelativeLayout myGameLayout = (RelativeLayout) findViewById(R.id.game_RelativeLayout);
        TextView display = (TextView) findViewById(R.id.display);

        display.setText("Replaying the pattern...");
        myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.white));

        while(i < pattern.length()){
            temp = pattern.substring(i, i+1);

            if(temp.equals("r")){
                //Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
                myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.game_red));
            }
            else if(temp.equals("b")){
                //Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
                myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.game_blue));

            }
            else if(temp.equals("y")){
                //Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
                myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.game_yellow));

            }
            else{
                // error, should not occur
                myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.white));
                Toast.makeText(getApplicationContext(), "Error, character not recognized: " + temp, Toast.LENGTH_SHORT).show();
            }
            i++;
            // WAIT 1 SECOND, SO USER CAN OBSERVE COLOR PATTERN
        }
        myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.white));
        display.setText("");
    }

The most popular answer I could find appears here ( How to call a method after a delay in Android ) , which I have attempted to implement below:

public void replayPattern2(View view){

        int i=0;
        //String temp;
        int delay = 1000;
        //RelativeLayout myGameLayout = (RelativeLayout) findViewById(R.id.game_RelativeLayout);
        //TextView display = (TextView) findViewById(R.id.display);

        display.setText("Replaying the pattern...");
        myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.white));

        final Handler handler = new Handler();
        patternIndex = 0;

        while(patternIndex < pattern.length()-1){
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    runCount++;
                    String temp = pattern.substring(patternIndex, patternIndex+1);

                    if(temp.equals("r")){
                        Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
                        myGameLayout.setBackgroundColor(getResources().getColor(R.color.game_red));
                    }
                    else if(temp.equals("b")){
                        Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
                        myGameLayout.setBackgroundColor(getResources().getColor(R.color.game_blue));
                    }
                    else if(temp.equals("y")){
                        Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
                        myGameLayout.setBackgroundColor(getResources().getColor(R.color.game_yellow));
                    }
                    else{
                        // error, should not occur
                        myGameLayout.setBackgroundColor(getResources().getColor(R.color.green));
                        Toast.makeText(getApplicationContext(), "Error, character not recognized: " + temp, Toast.LENGTH_SHORT).show();
                    }
                }
            }, delay);
            patternIndex++;
        }
        //myGameLayout.setBackgroundColor(this.getResources().getColor(R.color.white));
        display.setText("runcount = " + runCount);

    }

From what I can observe, the code is actually going through the correct number of loops, but it's still not actually pausing between iterations and showing the intermediate color changes. There's probably something minute I'm missing, but I've spent close to 12 hours solely debugging and researching this mid-loop delay. Any help would be greatly appreciated!

Community
  • 1
  • 1

1 Answers1

0

The reason that your replayPattern2() function isn't working is that even though you post the Runnable with a delay, you don't have any delay in your for loop before moving on to the next character and posting the next Runnable, so you end up with all your Runnables scheduled to run one after another, 1000 ms after your program starts.

You can modify your Runnable so that it runs and then posts itself back to the Handler with a delay when it's finished, checking for the end of the String. At the start you only need to post a single Runnable, so you can get rid of the for loop:

final int delay = 1000; // delay needs to be declared final to access it inside the Runnable

final Handler handler = new Handler();
patternIndex = 0;

handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        runCount++;
        String temp = pattern.substring(patternIndex, patternIndex+1);

        if(temp.equals("r")){
            Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
            myGameLayout.setBackgroundColor(getResources().getColor(R.color.game_red));
        }
        else if(temp.equals("b")){
            Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
            myGameLayout.setBackgroundColor(getResources().getColor(R.color.game_blue));
        }
        else if(temp.equals("y")){
            Toast.makeText(getApplicationContext(), temp, Toast.LENGTH_SHORT).show();
            myGameLayout.setBackgroundColor(getResources().getColor(R.color.game_yellow));
        }
        else{
            // error, should not occur
            myGameLayout.setBackgroundColor(getResources().getColor(R.color.green));
            Toast.makeText(getApplicationContext(), "Error, character not recognized: " + temp, Toast.LENGTH_SHORT).show();
        }
        patternIndex++;
        if(patternIndex <= pattern.length()-1)
            handler.postDelayed(this, delay); // the Runnable posts itself to the Handler if not at the end of the string yet
    }

}, delay);
samgak
  • 23,944
  • 4
  • 60
  • 82