Search code examples
javaandroidcountdowntimerandroid-handler

Replacing CountDownTimer with Handler and Runnable for better performance


I've got game based on CountDownTimer, which is continuously repeating countdowns. This countDown is counting time for user to react on some action related to number, if user reacts onFinish() is called by some clickListener or by itself if the time was up. Depending of succesCondition(), method success or fail is called and those methods are defining if game is still running.

OnCreate

loop = gameLoop(time).start();

MainActivity

public CountDownTimer gameLoop(int time){
    return new CountDownTimer(time, time+100) {
        @Override
        public void onTick(long millisUntilFinished) {

        }

        @Override
        public void onFinish() {
            if (!Conditions.succesCondition(number)) {
                success();
            } else {
                fail();
            }
        }
    };
}

public void success() {
    loop.cancel();
    scoreCount++;
    animation.start();
}

public void fail(){
   loop.cancel();
}

However this timer runs on Main thread and that provides well known issue skipped xx frames, your app might be doing too much work on its main thread and I found that this is common issue for CountDownTimer and replacing it with Handler is a solution.

I can't put this timer in AsyncTask because it performs mainly UI related tasks (TextViews, TextSwitcher, some progressBar etc. in success() method. I didn't put that in code in those methods for more clean view of the main problem. I'm trying to reconstruct CountDownTimer- like concept with handler and runnable to replace my Timer, but I'm actually stuck with nothing. As you can see I'm using only onFinish method, onTick is not necessary.


Solution

  • OK. I finally figured out how to handle it with handler (hehe):

    public void startGameAction() {
    
        //My game actions
    
        handler = new Handler();
        runnable = () -> {
            if (!Conditions.succesCondition(number)) {
                success();
            } else {
                fail();
            }
        };
        handler.postDelayed(runnable,time);
    }
    
    public void success(){
            handler.removeCallbacks(runnable);
            handler = null;
    
            scoreCount++;
            //other stuff
            startGameAction();
        }
    
     private void fail() {
        handler.removeCallbacks(runnable);
        //other stuff
    }
    

    onCreate only startGame call, handler and runnable defined as class fields

    startGameAction();