Home » Android » Handler postDelayed executes few times

Handler postDelayed executes few times

Posted by: admin November 1, 2017 Leave a comment

Questions:

I have a SeekBar on my UI. I want to report its value in a TextView, when I change its position. In this TextView, I also want to provide an information, how long is the position still (in seconds). I thought, the run method in a Runnable, will run only once, but it runs couple of times per one postDelayed execution. No matter the delay is 1s or 10s long. How to force it to run only one time? Should I make a thread?

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    y=0;
    myHandler.postDelayed(new Runnable(){
    @Override
    public void run(){
           myHandler.postDelayed(this, 1000);
           progressIndicator.setText("Covered: " + progressX.getProgress() + "/" + progressX.getMax() + " position is still for " + y + " seconds");
                    y+=1;
           }
    },1000);
}

EDIT:
removeCallbacks helped a bit. The code works correctly, but only on the first progressChange now, I’ll try to figure it out tomorrow.

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
  y=0;
  myHandler.postDelayed(new Runnable(){
           @Override
           public void run(){
           myHandler.removeCallbacks(this);
           y+=1;
           progressIndicator.setText("Covered: " + progressX.getProgress() + "/" + progressX.getMax() + " position is still for " + y + " seconds");
           myHandler.postDelayed(this, 5000);
           }
   },5000);
 }
Answers:

onProgressChanged is called a couple of times when the seekbar is moved, that means that you have several pending postDelayed()

To solve it, each time you call postDelayed() you should call first removeCallbacks() that ensures only one pending postDelayed() will be active

But you will need to create the Runnable and the Handler instances in the class fields and not on the onProgressChanged body

Something like this:

     private Handler myHandler = new Handler();
     private Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                // do something //
                myHandler.removeCallbacks(myRunnable);
                myHandler.postDelayed(myRunnable, 1000);
            }
        };




     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
         // do something //
         myHandler.removeCallbacks(myRunnable);
         myHandler.postDelayed(myRunnable, 1000);
}

Questions:
Answers:

You’re basically using a pattern to repeat the Runnable forever. Inside your Runnable, you have a call to mHandler.postDelayed(this, 1000);. The this in this context is the new Runnable that you created initially. That means that the Runnable will schedule another run one second later each time it executes.

If you only want it to run once, you should just remove the mHandler.postDelayed(this, 1000); line.

You should also ensure that you call mHandler.removeCallbacks(null) in onDestroy() to ensure you don’t cause a memory leak since your Runnable will hold a reference to your Activity through the TextView reference.