user1417127
user1417127

Reputation: 1645

Android how to update value of ProgressBar?

My activity have a ProgressBar. When start activity, I'll check value get from another place and update to ProgressBar. Here's my code:

final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar_detail);
final TextView progressText = (TextView) findViewById(R.id.progressText_detail);
final ImageView btnCancel = (ImageView) findViewById(R.id.imgCancel_detail);
progressBar.setVisibility(View.VISIBLE);
progressText.setVisibility(View.VISIBLE);
btnCancel.setVisibility(View.VISIBLE);
Thread t = new Thread() {
    public void run() {
        ((Activity) ctx).runOnUiThread(new Runnable() {
            public void run() {
                int oldProgress = 0;
                while (progressBar.getProgress() < 100) {
                    int value = Downloader.progress.get(gameId+ "");
                    if (value != oldProgress) {
                        oldProgress = value;
                        progressBar.setProgress(value);
                        progressText.setText(value + " %");
                    }
                }
            }
        });
    }
};
t.start();

Value of ProgressBar i get from int value = Downloader.progress.get(gameId) and it's correct. But when I run this code, the activity is not responding and not showing anything (but app not crash). Seems like the thread to update ProgressBar running and block the UI thread so the activity layout is not showing.

What's wrong with my code? What is the correct way to update ProgressBar in this situation?

Upvotes: 10

Views: 65129

Answers (4)

Luis
Luis

Reputation: 1302

You are running a while (progressBar.getProgress() < 100) in the UI thread (you use runOnUiThread) so UI thread will be blocked (and nothing painted) until this loop finish.

You can:

  • Put the runOnUiThread inside the loop and, maybe, a sleep inside de runOnUiThread call. However, it is not the preferred kind of solution since you are using too much CPU to just look for a value change. The sleep approach it a bit ugly but solves the cpu problem. It would be something like::

    Thread t = new Thread() {
        public void run() {
        int oldProgress = 0;
    
        while (progressBar.getProgress() < 100) {
                ((Activity) ctx).runOnUiThread(new Runnable() {
                    public void run() {
                        int value = Downloader.progress.get(gameId+ "");
                        if (value != oldProgress) {
                            oldProgress = value;
                            progressBar.setProgress(value);
                            progressText.setText(value + " %");
                        }
                    }
                }
                Thread.sleep(500);
            }
        });
      }
    };
    
  • Update the progress bar in an event way so you only call (in the UI thread) the update code when progress changes. It is the preferred way.

Upvotes: 14

lookashc
lookashc

Reputation: 899

You can auto-advance progress bar using RXJava.

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    if (autoProgress) {
        autoProgressSubscriber = Observable.interval(0, 1000/60, TimeUnit.MILLISECONDS) //~60fps
                    .map(index -> calculateAutoProgress())
                    .subscribe(progress -> {
                        if (progressBar != null) {
                            progressBar.setProgress(progress);
                        }
                    });
    }
}

@Override
protected void onDetachedFromWindow() {
    if (autoProgress) {
        autoProgressSubscriber.unsubscribe();
    }
    super.onDetachedFromWindow();
}

Upvotes: 1

psykid
psykid

Reputation: 448

I usually use this code:

private int mProgressStatus;
private Handler mHandler = new Handler();

public void startProgress(View view) {
    final ProgressBar progressBar = (ProgressBar) findViewById(R.id.horizontal_progress);
    mProgressStatus = 0;
    progressBar.setProgress(mProgressStatus);

    //progressBar.setVisibility(View.VISIBLE);
    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(final Void... params) {
            while (mProgressStatus < 100) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mProgressStatus += 15;
                mHandler.post(new Runnable() {
                    public void run() {
                        progressBar.setProgress(mProgressStatus);
                    }
                });
            }
            return null;
        }

    }.execute();
}

Hope this helps

Upvotes: 1

AkashG
AkashG

Reputation: 7888

Try with:

    int currentPosition=0;
    int total=mediaPlayer.getDuration();
    while(mediaPlayer!=null && currentPosition<total){
        try{
            if(progressEnable){
                Thread.sleep(1000);
                currentPosition=mediaPlayer.getCurrentPosition();
                long pos=1000L * currentPosition/total;
                Log.d("thread pos", pos+"");
                progressSeekBar.setProgress((int) pos);
            }
        }
        catch (Exception e) {
        }
    }

Declare progressEnable globally:

private boolean progressEnable=true;

Upvotes: 2

Related Questions