8

My onProgressChanged()-event doesn't get fired when I set the progress of a SeekBar programmatically, but it does get fired perfectly fine when I physically move the SeekBar slider.

I'd expect the event to fire when using setProgress() - the Android Developer Reference even states that:

public abstract void onProgressChanged (SeekBar seekBar, int progress, boolean fromUser)

Notification that the progress level has changed. Clients can use the fromUser parameter to distinguish user-initiated changes from those that occurred programmatically.

Some code snippets from my project:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_activity);               

    final SeekBar mySeekBar = ((SeekBar) findViewById(R.id.mySeekBar));
    
    mySeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
        @Override
        public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
            // Do some stuff
        }
    }
}


@Override
protected void onResume() {
    super.onResume();

    final SeekBar mySeekBar = ((SeekBar) findViewById(R.id.mySeekBar));
    mySeekBar.setProgress(someValue); // This SHOULD trigger onProgressChanged(), but it doesn't...
}
Community
  • 1
  • 1
Magnus
  • 17,157
  • 19
  • 104
  • 189

10 Answers10

9

Stumbled across the same problem just now.

In my case, the onProgressChanged did not get fired simply because the value did not actually change. I was setting the same value as the current one (0 :)

(and I don't see anything wrong with your code)

Romuald Brunet
  • 5,595
  • 4
  • 38
  • 34
6

+1 for Romuald Brunet's answer:

Here was my "hack" to fix it:

        <SeekBar android:id="@+id/seekbar" 
            android:layout_width="match_parent" 
            android:layout_height="wrap_content"  
            android:progress="1"
            android:max="200" />

Note the progress="1", set the default progress in the layout to 1, then in my code when I actually default it to 0, a change in the progress occurs and the onProgressChanged() event fires.

Aaron Bar
  • 611
  • 1
  • 7
  • 20
3

My listener didn't fire because I was calling setProgress() BEFORE setting the listener

adiga
  • 34,372
  • 9
  • 61
  • 83
zevero
  • 2,312
  • 21
  • 12
1

SeekBar.OnSeekBarChangeListener.onProgressChanged is only called when the progress is actually changed, not necessarily when setProgress is called - this only happens if the new progress is different from the last.

Looking at the source of SeekBar, which extends AbsSeekBar which in turn extends ProgressBar, we can see that a call to setProgress() doesn't fire the onProgressChanged() event unless the new progress is different from the previous one as seen in the source below.

/* 
    Snippet from ProgressBar.java 
*/

public void setProgress(int progress, boolean animate) {
    setProgressInternal(progress, false, animate);
}


synchronized boolean setProgressInternal(int progress, boolean fromUser, boolean animate) {
    if (mIndeterminate) {
        // Not applicable.
        return false;
    }

    progress = MathUtils.constrain(progress, mMin, mMax);
    if (progress == mProgress) {
        // No change from current.
        return false;
    }

    mProgress = progress;
    refreshProgress(R.id.progress, mProgress, fromUser, animate);
    return true;
}
Magnus
  • 17,157
  • 19
  • 104
  • 189
jpihl
  • 7,941
  • 3
  • 37
  • 50
1

Set progress=10 in xml file as shown below:

<SeekBar android:id="@+id/seekbar" 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content"  
  android:progress="10"
  android:max="100" />

Then in main file write below code:

new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            seekbar.setProgress(50)
                        }
                    }, 100);

Give delay less so that it doesn't affect the UI.

Snehal
  • 543
  • 7
  • 11
1

You need to ensure the value has definitely changed, otherwise it won't be picked up. Put in 2 lines. The 1st not wanted. The 2nd desired.

seekbar.setProgress(7); // Necessary to force the change to desired
seekbar.setProgress(50); // Desired progress
TomV
  • 1,157
  • 1
  • 13
  • 25
0

one possible workaround is to create own widget extending Seekbar and implementing two methods for your needs:

    private OnSeekBarChangeListener onSeekBarChangeListener;

    @Override
    public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
        super.setOnSeekBarChangeListener(l);
        onSeekBarChangeListener = l;
    }

    @Override
    public void setProgress(int progress) {
        super.setProgress(progress);
        if (onSeekBarChangeListener != null) {
            onSeekBarChangeListener.onProgressChanged(this, progress, false);
        }
    }
Lukas
  • 1,216
  • 12
  • 25
0

The accepted answer didn't work for me because it stopped getting fired when the progress is set to 1 programmatically (which is the same bug).

What I did instead was to invoke the onProgressChanged() myself. I the seek bar is a member variable.

void setProgressValue(int progress){
    if(progress == 0){ //the default progress is 0. if i set it to 0 again the call back wont be invoked
        mSeekBar.setProgress(progress);
        onProgressChanged(progress,mSeekBar,false);
    }
}

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    //things to be done when the call back is received
}

Posting in the hope of helping someone later.

hushed_voice
  • 3,161
  • 3
  • 34
  • 66
-1

I can confirm with certainty that setProgress works on Android version 6.0.1.

Another StackOverflow answer said it was a bug. If this was true, it is definitely no longer the case.

This code works on my test setup:

@Override
public void onResume() {
    super.onResume();

    SeekBar seekBar = (SeekBar)findViewById(R.id.seek_bar);
    seekBar.setProgress(seekBar.getProgress());
}

As expected, the SeekBar's OnSeekBarChangeListener is getting called.

For troubleshooting, make sure that you set the listener properly using setOnSeekBarChangeListener() and make sure you implement the interface functions. Other SO answers seem to indicate that you should only call setProgress() from the UI thread. This answer shows how that can be done.

Community
  • 1
  • 1
Nicholas Miller
  • 4,205
  • 2
  • 39
  • 62
  • @Downvoter. (or anyone else). I would like to know if there is an error in this answer so that it can be corrected. Thanks! – Nicholas Miller Feb 15 '19 at 22:33
  • if (progress == mProgress) { // No change from current. return false; } this code is from ProgressBar.java you can check it yourself. If the progress is same as earlier it won't give you a callback – hushed_voice May 24 '19 at 07:53
-1

simply call

 mySeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
    @Override
    public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
       int i=    arg0.getProgress();
     //youre seekbar.setProgress(i);
    }
}
Hemanth Kumar
  • 257
  • 3
  • 12