Android如何更新ProgressBar的值?

9

我的Activity中有一个进度条(ProgressBar)。当启动Activity时,我会检查从另一个地方获取的值,并更新到进度条中。以下是我的代码:

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

我从int value = Downloader.progress.get(gameId)获取到的ProgressBar的值是正确的。但当我运行这段代码时,活动没有响应,也没有显示任何东西(但应用程序没有崩溃)。似乎更新ProgressBar的线程正在运行并阻塞UI线程,因此活动布局未显示。

我的代码有什么问题?在这种情况下更新ProgressBar的正确方法是什么?


尝试使用AsyncTask,例如 http://stackoverflow.com/questions/11339847/how-to-add-progressdialog/11339895#11339895 - Nermeen
请查看此教程:http://samir-mangroliya.blogspot.in/p/android-asynctask-example.html - Samir Mangroliya
如果你真的想使用线程,请尝试Thread.setPriority(NORMAL-1);否则请使用AsyncTasks,它们非常有用。 - Korniltsev Anatoly
4个回答

12

您正在UI线程中运行while (progressBar.getProgress() < 100),因此UI线程将被阻塞(且没有任何绘制),直到此循环完成。

您可以:

  • 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.


如何以事件方式更新进度条?您能具体说明一下吗? - user1417127
谢谢。你说得对,循环在UI线程内部。你也说得对,因为我的应用程序运行非常缓慢,所以使用了太多的CPU。你能告诉我如何以事件方式更新进度条吗? - user1417127
1
不确定 Downloader 是做什么的。它可能有一个 ondownload 事件(或类似的东西),您可以提交一个监听器,该监听器会更新 progressBar。如果没有,您可以采用一种有点丑陋的睡眠方法。让我编辑我的答案,以放置一个示例。 - Luis

2

请尝试以下方法:

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

全局声明progressEnable:

private boolean progressEnable=true;

1
我通常使用这段代码:

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

希望这有所帮助。

1
你可以使用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();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接