android progressBar does not update progress view/

2019-01-06 15:26发布

问题:

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?

回答1:

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);


回答2:

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.



回答3:

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);
      }
});


回答4:

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



回答5:

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.



回答6:

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



回答7:

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)



回答8:

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));


回答9:

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.



回答10:

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;
}


回答11:

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;
  }
}


回答12:

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.



回答13:

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); <--


回答14:

For me worked if I set setVisibility() to visible before each setProgress()

setVisibility(View.VISIBLE);
setProgress(progress);