Add delay to a loop in android without stalling the UI Thread

Tags: ,



I have been looking all over the Android Studio Docs and StackOverflow, but I can not seem to find a way to do the equivalent of what is done in IOS here: Adding Delay In A For Loop Without Blocking UI in Android.

I have tried to use a Handler, but instead of running the code like:

// Iteration 1
// Delay of 500ms
// Iteration 2
// Delay of 500ms
// ...

The code seems to be run as follows:

// Iteration 1
// Iteration 2
// Delay of 500ms
// next state

The code I am using is stuctured like this:

Handler myHandler = new Handler();
while (someCondition) {
    myHandler.postDelayed(new Runnable() {
        public void run() {
            myFunction();
        }
    }, 500);
}

The behavior I see when running this Activity is that is skips it, and after 500ms it goes to the next Activity (with expected result) but without showing the user what’s happening.

How would I delay the loop so the user can see what’s happening?


To clarivy:

The current state (after moveCard()) needs to be shown for x ms before going though the logic of my while loop again.

This is done untill the final state is has been reached.

Then the next Activity is started.


public void onCreate (Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.horserace_game);

    this.cardDeck = findViewById(R.id.deck);
    this.game_ended = false;

    this.deck = new Deck();
    this.aces = new ArrayList<>();
    this.acesPos = new ArrayList<>();
    this.hidden = new ArrayList<>();

    // Remove all Aces from deck and put them in aces
    //resetDeck creates a deck ordered on Face (so Ace SDHS, Two SDHS etc, which is handy for this purpose.
    this.deck.resetDeck(1);
    for (int i = 0; i < 4; i++) {
        this.aces.add(this.deck.removeCard(0));
        // Add a new pos for card
        this.acesPos.add(0);
    }

    // Shuffle the deck
    this.deck.shuffleDeck();

    // Get 7 cards from the top of the deck to put on the
    // side of the track and place them face down on the screen
    for (int i = 0; i < 7; i++) {
        this.hidden.add(this.deck.removeCard(0));
    }


    // Whilst the game is still running, pick a card from the deck and move the ace with the same suit
    while (!this.game_ended) {
        // Pick the next card from the deck
        this.next = this.deck.removeCard(0);
        cardDeck.setImageResource(getCardImage(next));
        // Find the ace with the same suit as this.next and set it's 'score'++
        for (Card ace : this.aces) {
            if (ace.getSuit().equals(next.getSuit())) {
                this.acesPos.set(ace.getSuit().ordinal(), this.acesPos.get(ace.getSuit().ordinal()) + 1);
                break;
            }
        }
        // Final state: the last ace now has a pos >7, this ace is the result. start new Activity
        if (this.acesPos.get(next.getSuit().ordinal()) > 7) {
            this.game_ended = true;
            Intent winner = new Intent();
            winner.putExtra("winner",next.getSuit().ordinal());

            setResult(RESULT_OK, winner);
            finish();
        // If the ace is not at it's final position, move it 
        // and pick a new card in the next iteration.
        } else {
            // Move card
            myHandler.postDelayed(new Runnable() {
                public void run() {
                    Log.e("run: ", "moveCard");
                    moveCard();
                }
            }, 500);
        }
    }
}

Answer

Maybe Creating Something like this should work,

protected static void startTimer() {
    timer.schedule(new TimerTask() {
        public void run() {
            mHandler.obtainMessage(1).sendToTarget();
        }
    }, 500);
}

public Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
         myFunction();
    }
};


Source: stackoverflow