Android: how to create delay in loop while still updating the UI
Use a Handler with a Runnable (which does one iteration of the loop in its run()) and postDelayed(Runnable r, long delayMillis)
for the delay. Count the iterations so you know when to stop and use the last one to removeCallbacks()
and call a method to do whatever needs to be once the dealing is done.
Something like
private final Handler mHandler = new Handler();
private int iLoopCount = 0;
private final Runnable rDealAndWait = new Runnable()
{
public void run()
{
if (dealtAHand())
{
++iLoopCount;
mHandler.postAtTime(this, SystemClock.uptimeMillis() + DEAL_DELAY);
}
else
{
doAfterAllHandsDealt();
}
}
};
private boolean dealtAHand()
{
if (i == CARD_COUNT) return false;
//human player
LoadCard(playerCards.get(iLoopCount), pCards.getCard(i));
playerCards.get(iLoopCount).setVisibility(View.VISIBLE);
playerCards.get(iLoopCount).setPadding(1, 1, 1, 1);
// etc
return true;
}
And then in the onCreate or wherever
dealtAHand();
mHandler.postAtTime(rDealAndWait, SystemClock.uptimeMillis() + DEAL_DELAY);
}
Daniel
Updated on July 09, 2022Comments
-
Daniel almost 2 years
This is my first post here so sorry if I don't format my question correctly. I am developing my first Android app and it is a card game. I've developed the same card game in C# using visual studio. In C#, in order to simulate action and delay when dealing, etc, I slept the thread for a given amount of time, then called the method Application.DoEvents() which forced the UI to update. However, in java, I cannot seem to find an answer to this problem.
I'll post some code from my deal() method, which I need to delay so it looks like the cards are actually being dealt in a circle, and not all at once since the computer goes so fast:
private void dealHelper() { Hand pCards = Referee.getHumanHand();
//show all cards in rotating order for(int i=0; i<CARD_COUNT; i++) { /////////////////////////////////////////////////////////////////////// // load each card into their appropriate ImageViews and make visible // /////////////////////////////////////////////////////////////////////// //human player LoadCard(playerCards.get(i), pCards.getCard(i)); playerCards.get(i).setVisibility(View.VISIBLE); playerCards.get(i).setPadding(1, 1, 1, 1); // allow discarded cards to be clickable discardCardImages.get(i).setPadding(1, 1, 1, 1); //computer 1 computer1Cards.get(i).setImageResource(R.drawable.cardskin); computer1Cards.get(i).setVisibility(View.VISIBLE); //computer 2 computer2Cards.get(i).setImageResource(R.drawable.cardskin); computer2Cards.get(i).setVisibility(View.VISIBLE); //computer 3 computer3Cards.get(i).setImageResource(R.drawable.cardskin); computer3Cards.get(i).setVisibility(View.VISIBLE); } }
I need a slight delay of about 500ms between each card that is displayed on the screen to simulate action. I've searched and searched and haven't a solution that works (or I understand). Any help would be much appreciated.
Thank You, Daniel
-
Daniel almost 13 yearsI've considered this solution, however I guess I didn't understand how it worked fully. When I tried to implement each card card deal into a Runnable, I get errors saying it can't access variables outside the method (such as i) and that 'i' isn't static? I need 'i' so the code knows which card to deal. I wasn't sure of a way around this.
-
Ben Williams almost 13 yearsYou should be able to declare a
private int i
field in the surrounding class and use that in the runnable. -
harism almost 13 yearsAnother way would be to do whole for -loop in a separate thread. There you can sleep safely without blocking UI and shoot commands to update card visibilities. You just have to do it using
runOnUiThread
. -
Daniel almost 13 yearsthanks for the tips @Ben and @harism, i'll try to implement your suggestions and let you know how it turns out!