0

I don't fully understand what is going on behind the scene, and therefore, what I can do to correctly code this issue. I'm looking for an explanation that will lead me to figure it out myself. This is just a fun home based project(I'm not a student), where I'm coding a turn based app. However, the battle scenes are randomly calculated durations, rather than turn based, so my desire is as follows:

  1. Present initial battle count on screen for 2 seconds
  2. Calculate first skirmish
  3. Present updated battle count on screen for 2 seconds
  4. Calculate 2nd skirmish
  5. ...
  6. ...
  7. Present Victory or Defeat on screen

The problem I'm having is that the app is performing as follows currently:

  1. Present initial battle count on screen
  2. Calculate all skirmishes
  3. Page displays null for the number, since it's apparently already returned?

Code looks like this:

void fightBattle(){
    setContentView(R.layout.brigands);
    boolean winnerDetermined = false;
    while(!winnerDetermined) {
        boolean brigandsWon = brigandsWon(player, brigandCount);
        if(brigandsWon) {
            player.removeWarriors(2);
        }
        displayWarriors(player);
        if(brigandsWon){
            if(player.getWarriors() < 2){
                winnerDetermined = true;
            }
        }
        if(!brigandsWon) {
            brigandCount = brigandCount / 2;
        }
        displayBrigands();
        if(brigandCount == 0){
            winnerDetermined = true;
        }
    }
}

private void displayWarriors(Player player){
    final Player currentPlayer = player;
    new CountDownTimer(2000, 2000) {
        public void onTick(long millisUntilFinished) { }
        public void onFinish() {
            setContentView(R.layout.warriors);
            TextView warrior_count_tv = findViewById(R.id.warrior_count_tv);
            warrior_count_tv.setText(currentPlayer.getWarriors());
        }
    }.start();
}

private void displayBrigands(Player player){
    new CountDownTimer(2000, 2000) {
        public void onTick(long millisUntilFinished) { }
        public void onFinish() {
            setContentView(R.layout.brigands);
            TextView brigand_count_tv = findViewById(R.id.brigand_count_tv);
            brigand_count_tv.setText(Integer.toString(brigandCount));
        }
    }.start();
}

Ultimately, what I want to see is something like the below sudo-code:

displayPage1For2Seconds;
while(somethingIsTrue){
    calculateNumber;
    displayPage2For2Seconds;
    displayPage3for2Seconds;
}
displayPage4For2Seconds;
user
  • 86,916
  • 18
  • 197
  • 190
Ryan G
  • 380
  • 1
  • 11

1 Answers1

0

Calculate all skirmishes

Your current code does this because the while loop doesn't actually stops to wait. The flow will be like this:

enter while loop -> call displayWarriors() -> create CountDownTimer() to do something after 2 seconds -> return to while loop -> call displayBrigands() -> create CountDownTimer() to do something after 2 seconds -> return to while loop -> do the same until you exit while

With this code you'll end up with a bunch of CountDownTimers that are created and executed at the same(almost) time so after two seconds they all try to set a view to some value(with an indefinite behavior like you mention it happens).

There are several ways to do what you want. You could use a Thread for example:

void fightBattle(){
    setContentView(R.layout.brigands);
    new Thread(new Runnable() {
         public void run() {
             // I assume R.layout.brigands is the initial screen that you want to show for 2 seconds?!? In this case wait 2 seconds
             TimeUnit.Seconds.sleep(2);    
                 boolean winnerDetermined = false;
    while(!winnerDetermined) {
        // ...  
        // from your code it seems you want to show this for 2 seconds?
        displayWarriors(player);
        TimeUnit.Seconds.sleep(2);     
        //...
        displayBrigands();
        // also show this for 2 seconds
        TimeUnit.Seconds.sleep(2);    
        // ... 
    }
         }
    }).start();
}

Then your display methods will be something like this:

private void displayWarriors(Player player){
    // you need to wrap this code in a runOnUiThread() method(from the activity)
    // because we are on a background thread and we are changing views!
    final Player currentPlayer = player;
    setContentView(R.layout.warriors);
    TextView warrior_count_tv = findViewById(R.id.warrior_count_tv);
    warrior_count_tv.setText(currentPlayer.getWarriors()); 
}

Another approach would be to use a Handler and break your code in Runnables that you then schedule at appropriate times.

user
  • 86,916
  • 18
  • 197
  • 190
  • Thank you Luksprog, while the code you posted did not work for me, you explained what I was doing incorrectly and pointed me toward using a Handler. I was able to use a Handler, using the postDelay method, with a class variable to manage the delay, to delay and order screen changes. – Ryan G Mar 19 '19 at 11:46
  • @RyanGriffin Handler was another way of doing things as I mentioned. What happened when you tried the code I posted? – user Mar 19 '19 at 12:28