android progressBar does not update progress view/drawable
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.getThres开发者_StackOverflow中文版hold() : 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?
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);
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.
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);
}
});
For me, calling setMax()
before setProgress()
worked for some reason.
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.
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
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)
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;
}
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));
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.
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;
}
}
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.
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); <--
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);
}
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);
}
});
}
});
For me worked if I set setVisibility() to visible before each setProgress()
setVisibility(View.VISIBLE);
setProgress(progress);
精彩评论