问题
I am writing a maze game, and one of its features is "Show solution". The solution may contain many steps, I am using a for loop to iterate every step, in order to show it clear to a player, I wish it can pause one second around after every step. I know the delay operation cannot be put in UI thread, so I have tried several async delay approach. Unfortunately, because of its async nature, if the solution has more than one step, the UI cannot update till the last step finish. That's not I want certainly.
I have tried handler.postDelayed
approach, new Timer().schedule
approach.
public void showSolutionClick(View view) {
int stage = currentGame.currentStage;
int[][] solution = GameMap.solutionList[stage];
drawStage(stage);
for(int[] step: solution) {
ImageView v = (ImageView)findViewById(viewIdList[step[0]][step[1]]);
setTimeout(() -> {v.callOnClick();}, 1);
}
}
private void setTimeout(Runnable r, int seconds) {
Handler handler = new Handler();
handler.postDelayed(r, seconds * 1000);
}
Maybe a synchronous delay approach is what I need, and it must not block the ui update.
update: CountDownTimer is suitable for this situation. In fact, I have seen a CountDownTime answer at other questions, I should have tried that approach first before I ask. Thank you all who have given a response. Here's my final code:
public void showSolutionClick(View view) {
int stage = currentGame.currentStage;
int[][] solution = GameMap.solutionList[stage];
drawStage(stage);
int stepTotal = solution.length;
int stepPause = 1000;
int timeTotal = (stepTotal + 1) * stepPause;
new CountDownTimer(timeTotal, stepPause) {
int stepIndex = 0;
public void onTick(long timeRemain) {
int[] pos = solution[stepIndex];
ImageView v = (ImageView)findViewById(viewIdList[pos[0]][pos[1]]);
v.callOnClick();
stepIndex += 1;
Log.d("time remain:", "" + timeRemain / 1000);
}
public void onFinish() {
Log.d("final step", ":" + (stepIndex - 1));
}
}.start();
}
回答1:
You can use a countdown timer.
new CountDownTimer(30000, 1000){
public void onTick(long millisUntilFinished){
doUpdateOnEveryTick()
}
public void onFinish(){
doActionOnFinish()
}
}.start();
回答2:
Try something like this,
public void showSolution(View view) {
// Do something long
Runnable runnable = new Runnable() {
@Override
public void run() {
int stage = currentGame.currentStage;
int[][] solution = GameMap.solutionList[stage];
drawStage(stage);
for(int[] step: solution) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
ImageView v = (ImageView)findViewById(viewIdList[step[0]][step[1]]);
setTimeout(() -> {v.callOnClick();}, 1);
}
});
}
}
};
new Thread(runnable).start();
}
来源:https://stackoverflow.com/questions/56324121/is-there-an-approach-which-can-delay-certain-seconds-between-every-function-call