Is there an approach which can delay certain seconds between every function call which need to update ui components?

自古美人都是妖i 提交于 2019-12-11 14:57:21

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!