25

two Bars which shows the progress of a game. If the user get points or time is up etc the progressBars should be updated:

private TextView tv;
private ProgressBar levelHoldBar;
private ProgressBar levelUpBar;

//...
private void updateViews() {

    // ...
    levelHoldBar.setMax(currentLevel.getThreshold());
    levelHoldBar.setProgress(currentPoints > currentLevel.getThreshold() ? currentLevel.getThreshold() : currentPoints);

    levelUpBar.setMax(nextLevel.getThreshold());
    levelUpBar.setProgress(currentPoints > nextLevel.getThreshold() ? nextLevel.getThreshold() : currentPoints);

    tv.setText(currentPoints+"/"+currentLevel.getThreshold());

    Log.d(TAG, "hold prog/max "+levelHoldBar.getProgress()+"/"+levelHoldBar.getMax());
    Log.d(TAG, "up   prog/max "+levelUpBar.getProgress()+"/"+levelUpBar.getMax());
}

ie. Outputs:

12-03 17:48:33.918: DEBUG/MainActivity(6829): hold prog/max 20/20
12-03 17:48:33.918: DEBUG/MainActivity(6829): up   prog/max 20/50

The Log.d(...) in the end shows ALWAYS the correct values, but SOMETIMES the visual bars of the progressBars do not show the correct progesses. They show progresses that had been set previously even if the getters for "max" and "progress" return correct values (in the example the bar shows about 20% (instead of 100%) for the levelHoldBar and about 2% (instead of 40%) for the levelUp-bar). I cannot figure out, why the log-output is correct but the drawables are wrong!? The TextView (tv) is updated correctly! Whats going on here? How can I fix that?

Stuck
  • 11,225
  • 11
  • 59
  • 104
  • Okay, dumb questions first - 1) you're updating in the UI thread, and 2) you don't have any custom drawing functions anywhere for anything? – EboMike Dec 03 '10 at 17:16
  • yes, im running it on UI thread and I dont have any custom drawings. It uses always the same call-stack for updating and sometimes the bars are updated and sometimes they are not.. this is strange^^ – Stuck Dec 03 '10 at 17:23
  • Okay. Something is fishy. What happens when you simplify your activity to, for example, modify the progress bar to "previous value + 1" every time you press a button? ProgressBars are very simple, so we need to go from a simple setup to what you currently have and find out at which point it breaks. – EboMike Dec 04 '10 at 04:26
  • Show how you're calling updateViewS(). You're almost certainly racing in some thread. – Falmarri Dec 04 '10 at 05:17
  • See other comment.. there I posted how I call the updateViews() on the UI Thread... but the problem is an unexpected behaviour of the ProgressBar: see my own answer... seems like a bug. I have reported it. Maybe you can confirm it. API Level 7 – Stuck Dec 04 '10 at 05:28
  • http://code.google.com/p/android/issues/detail?id=12945. Nice. I subscribed to it. – EboMike Dec 04 '10 at 05:34
  • I am facing issue with SeekBar can you please help me... here is my question https://stackoverflow.com/questions/54692981/android-music-seekbar-is-not-working-idle – VikaS GuttE Feb 23 '19 at 17:29

16 Answers16

52

SOLUTION: It's a Bug in ProgressBar!

finally... I think I found the solution...

this does not work as one would expect:

bar.setMax(50);
bar.setProgress(20);
bar.setMax(20);
bar.setProgress(20);

The setProgress(...) seems to not trigger the update on the drawable if the same value is passed again. But it's not triggered during the setMax, too. So the update is missing. Seems like a Bug in the android ProgressBar! This took me about 8 hours now.. lol :D

To solve this, I'm just doing a bar.setProgress(0) before each update... this is only a workaround, but it works for me as expected:

bar.setMax(50);
bar.setProgress(20);
bar.setProgress(0); // <--
bar.setMax(20);
bar.setProgress(20);
Stuck
  • 11,225
  • 11
  • 59
  • 104
  • 2
    Its already there since then: http://code.google.com/p/android/issues/detail?id=12945 – Stuck Jul 10 '11 at 18:54
  • Are you sure that the second setMax is 20 ? Or should it be 50 ? – taxeeta Jul 26 '13 at 05:46
  • 3
    its very bad bug for progressbar..10 hours to find this patched. – Ketan Mehta Oct 30 '13 at 07:07
  • 1
    @Stuck i have this issue with a circular progress bar where calling setMax does not work, is there a work around? Though it does work with a horizontal progress bar .. – Rat-a-tat-a-tat Ratatouille Mar 31 '14 at 06:08
  • 1
    @Rat-a-tat-a-tatRatatouille I think it would be best to start a new question for it. – Stuck Apr 01 '14 at 08:16
  • 7
    Sadly, this still is a bug even after 4 years. Setting just bar.setProgress(0) doesn't work. – TheOnlyAnil Mar 07 '15 at 19:27
  • 2
    4/9/2017 Issue still present. I called `setProgress` in the `post` action and it seems to have solved the problem for now. – Abluescarab Apr 09 '17 at 10:18
  • 1
    @Rat-a-tat-a-tatRatatouille @Stuck the fix posted by you @Stuck didn't help for the circular progress view :(. However I was able to fix by using `android:useLevel="true"` in the `shape` inside the drawable set for `android:progressDrawable`. – gipsey Mar 13 '18 at 12:28
  • I am facing issue with SeekBar can you please help me... here is my question https://stackoverflow.com/questions/54692981/android-music-seekbar-is-not-working-idle – VikaS GuttE Feb 23 '19 at 17:28
  • What a solution!! this answer just saved me and my time thanks!! – Riddhi Shah Apr 02 '19 at 10:31
  • For me, what worked was using the API with the animate boolean flag to to true - eg. `bar.setMax(20, true);` Hope this helps someone. – anshajkhare Nov 24 '20 at 14:25
24

I was able to get this to work with View.post():

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    // ...

    mSeekBar.post(new Runnable() {
        @Override
        public void run() {
            mSeekBar.setProgress(percentOfFullVolume);
        }
    });
}

As with SKTs answer it is unclear to me why this should work when this does not

mSeekBar.setProgress(percentOfFullVolume);

However, it seems to be true up to and including Android Lollipop.

david.mihola
  • 12,062
  • 8
  • 49
  • 73
14

You can use a handler to update progressbar

Handler progressBarHandler = new Handler();

ProgressBar bar = (ProgressBar) findViewById(R.id.progressBar1);;

progressBarHandler .post(new Runnable() {

      public void run() {
          bar.setProgress(progress);
      }
});
SKT
  • 1,821
  • 1
  • 20
  • 32
  • Why would this help, he says he is updating already from the UI thread – User Nov 27 '12 at 12:08
  • 1
    @Ixx I too had this similar problem. This solved my prob. I thought it might help here. – SKT Nov 28 '12 at 09:49
  • Then it's probably because you are calling it in onCreate(). Then this also helps. – User Nov 28 '12 at 10:04
  • No. I made this call in onResume() – SKT Nov 28 '12 at 10:10
  • If you made the call in onResume and in UI thread, I don't know why the handler is necessary. AFAIK in onCreate is necessary to post because the layout is not finished. In onResume() the layout should be finished, isn't it? Maybe I'm missing something. – User Nov 28 '12 at 11:19
  • I tried progressbar.post(), runOnUiThread, nothing worked but this :/ – A. N Feb 19 '18 at 07:23
9

For me, calling setMax() before setProgress() worked for some reason.

Farbod Salamat-Zadeh
  • 19,687
  • 20
  • 75
  • 125
8

In my case, I create VerticalSeekBar, and solution of Stuck does not work. After hours, I have found a solution:

@Override
public synchronized void setProgress(int progress) {
    super.setProgress(progress);
    onSizeChanged(getWidth(), getHeight(), 0, 0);
}

Hope that help anyone.

nlt
  • 555
  • 7
  • 11
5

Create updateThumb(); method in VerticalSeekbar

public void updateThumb(){
     onSizeChanged(getWidth(), getHeight(), 0, 0);
}

And then call update thumb method after setting progress.

seekBar.setProgress((int) progress);
seekBar.updateThumb();

its work for me in verticalseekbar calss

saravanan
  • 1,082
  • 1
  • 15
  • 30
4

Make sure style for the progressBar is set to be style="@android:style/Widget.ProgressBar.Horizontal" otherwise it will show Indeterminate Progress

(Just in case it will help someone)

Humayoun
  • 51
  • 3
4

I have tried in many ways by calling setProgress in Thread, runOnUiThread, Handler, Runnable. All of them dont work.

So finally, set value of dialog.setIndeterminate(false); will work.

Once you set dialog.setIndeterminate(true); the progress WONT UPDATE AT ALL.

public static ProgressDialog createProgressDialog(Activity activity, int messageID, boolean cancelable) {
    ProgressDialog dialog = new ProgressDialog(activity, R.style.DialogButtonTint);
    dialog.setMessage(activity.getString(messageID));
    dialog.setIndeterminate(false);
    dialog.setMax(100);
    dialog.setSecondaryProgress(0);
    dialog.setProgress(0);
    dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    dialog.setCancelable(cancelable);
    dialog.show();
    return dialog;
}
Tuan Nguyen
  • 2,542
  • 19
  • 29
  • This modification works for me. It did need to setIndeterminate(false), if you set to true, it will run it's own animation. – Moses Nov 26 '21 at 06:32
1

Thanks Stuck for the post stating that there is an Android bug. I also have a vertical seek bar.

The issue was when I was changing the progress drawable. The drawable would be updated but the bar would be set to 0 and be a very small size. I was able to get it to resize with updateThumb(), but the progress was still at 0.

To set the progress back at the original value I added a mylayer.setLevel(...);. I found this by reading the source code of ProgressBar.doRefreshProgress(...). You might be able to do seekBar.getProgressDrawable.setLevel(...).

LayerDrawable mylayer = //new LayerDrawable()
seekBar.setProgressDrawable(mylayer);
seekBar.updateThumb();
seekBar.setProgress((int) chLevel);
mylayer.setLevel((int) (chLevel / MAX_LEVEL * 10000));
DanFredell
  • 59
  • 4
1

I tried all solutions listed, they did not work. Turns out... the real problem was my code was busy running, essentially blocking the UI thread. So the proper solution which instantly fixed the problem was... put my busy code inside an async task.

In my case I was loading several thousand record from XML into a SQLite database. Naturally I wanted to update the progress bar. Code that should have done this ( prg_bar.setProgress(iProgressPercentage) ) did nothing, and at the end of the load, the UI finally got a chance to run. Poof, progress bar goes from zero to 100.

Same code put into the onProgressUpdate() of the async task, wrapped around the same functional code, worked perfectly. This makes me very skeptical of the idea "that there's a bug in the progress bar code" and that setting the max and to zero or any of those things were ever more than a coincidental work around.

MotoRidingMelon
  • 2,347
  • 2
  • 21
  • 28
0

This worked for me...

OneFragmen.java

public class OneFragment extends Fragment{

public OneFragment() {
    // Required empty public constructor
}
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;

int progress=0;
private Handler handler = new Handler();
TextView txtProgress;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(
    LayoutInflater inflater, 
    ViewGroup container,
    Bundle savedInstanceState ) {

   View view =  inflater.inflate(R.layout.fragment_one, container, false);
    getActivity().setTitle(R.string.app_name);

   final ProgressBar spinner = 
       (ProgressBar) view.findViewById(R.id.outerProgressBar);
    Resources res = getResources();
    Drawable drawable = res.getDrawable(R.drawable.circular);
    txtProgress = (TextView)view.findViewById(R.id.txtProgress);
    spinner.setProgressDrawable(drawable);
    spinner.setSecondaryProgress(100);
    spinner.setMax(100);
    spinner.setProgress(0);

    new Thread(new Runnable() {

        @Override
        public void run() {
            while (progress < 100) {
                progress += 1;
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        spinner.setProgress(progress);
                        txtProgress.setText(progress + "%");
                    }
                });
                try {
                    Thread.sleep(28);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }).start();
    return view;
  }
}
Simone Poggi
  • 1,448
  • 2
  • 15
  • 34
0

Nothing here worked for me, so I've came with a bit different solution. I noticed that everything is working well until I try to change maximal value (calling setMax with different value).

My code:

class FixedSeekBar : SeekBar {

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    companion object {
        private const val PROGRESS_MAX = 1000000.toDouble()
    }

    private var mLastMaxValue: Int = 100

    override fun setMax(max: Int) {
        mLastMaxValue = max
        super.setMax(PROGRESS_MAX.toInt())
    }

    fun setProgressFixed(progress: Int) {
        setProgress((PROGRESS_MAX / mLastMaxValue * progress).toInt())
    }

    fun getProgressFixed(): Int {
        return (getProgress() / PROGRESS_MAX * mLastMaxValue).toInt()
    }

}

This works perfectly for me. I can call setMax as usually and I just need to replace getProgress and setProgress with getProgressFixed and setProgressFixed.

Do not override setProgress and getProgress. They are called internally.

My solution doesn't count with setMin. If you need it, change the code accordingly.

Václav Hodek
  • 638
  • 4
  • 9
0

if you love full progressbar

time_prg_bar.setMax(100);
time_prg_bar.setProgress(0); <--

if your progressbar empty

time_prg_bar.setMax(100);
time_prg_bar.setProgress(100); <--
Mr_Moradi
  • 354
  • 5
  • 9
0

everyone. in case of the exist progress and the new progress value is same, the progressbar is not update. so you set the new value as the near value, that is easy way.

@Override
public synchronized void setProgress(int progress)
{
    if (getProgress() == progress)
    {
        if (progress > 0)   progress -= 1;
        else                progress += 1;
    }

    super.setProgress(progress);
}
0

just to thank and enrich david.mihola answer's, we should run android classProgressBar update method setProgress(int) from a new dedicated Thread to avoid the annoying refresh issues that appears if run from UI Thread , this is specially true if you have an app which refresh really often your progressbar and still you want the value to be always applied . here is a working solution example , enjoy!(i got 10h before getting it done!)

progress_bar3.setSensorListener(new OnLeftRightSensorListener() {
                @Override
                public void onLeftSensorDetected() {
              /**some code**/
                }

                @Override
                public void onRightSensorDetected() {
                    /**some code**/
                }

                @Override
                public void onNothingDetected(){
                    
                    Log.d(TAG, "PROGRESS BAR NOTHING SENSOR has been detected we need to SET THE BAR TO ZERO .");
                    progress_bar3.post(new Runnable() {
                    @Override
                    public void run() {
                        progress_bar3.setProgress(0);
                    }
                        });
                }


            });
0

The only method that worked for me was the "post" method

progressBar.post(new Runnable() {
    @Override
    public void run() {
        progressBar.setProgress(value);
    }
});
Araucaria
  • 1
  • 3