ProgressBar是开发中用的一个显示进度条的控件。和其他控件不太一样的地方是,更新进度的函数可以在非UI线程调用并且生效。下面深圳问答网的师生来探讨一下这个问题。
学生问题:Android的子线程中不能更新UI,但为什么在子线程中可以更新ProgressBar呢?还有在ProgressBar上显示进度的文字,是不是也可以在子线程中去完成呢?
老师回答:
ProgressBar这些控件之所以可以在子线程中更新,是因为其底层自己实现了把更新UI的操作放到主线程中运行,包装之后,给你的感觉就是,它可以直接在子线程中更新了。
它的设置进度代码:
- @android.view.RemotableViewMethod
- public synchronized void setProgress(int progress) {
- setProgress(progress, false);
- }
-
- @android.view.RemotableViewMethod
- synchronized void setProgress(int progress, boolean fromUser) {
- if (mIndeterminate) {
- return;
- }
-
- if (progress < 0) {
- progress = 0;
- }
-
- if (progress > mMax) {
- progress = mMax;
- }
-
- if (progress != mProgress) {
- mProgress = progress;
- refreshProgress(R.id.progress, mProgress, fromUser);
- }
- }
复制代码 这是设置进度的方法,中间调用了refreshProgress来设置进度,我们再跟进refreshProgress方法:- private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
- if (mUiThreadId == Thread.currentThread().getId()) {
- doRefreshProgress(id, progress, fromUser, true);
- } else {
- if (mRefreshProgressRunnable == null) {
- mRefreshProgressRunnable = new RefreshProgressRunnable();
- }
-
- final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
- mRefreshData.add(rd);
- if (mAttached && !mRefreshIsPosted) {
- post(mRefreshProgressRunnable);
- mRefreshIsPosted = true;
- }
- }
复制代码
它先判断了一下,当前线程是否是主线程,如果是,则直接更新,如果不是,则用
- post(mRefreshProgressRunnable);
复制代码 的方法,把更新进度的方法扔到主线程执行。- private class RefreshProgressRunnable implements Runnable {
- public void run() {
- synchronized (ProgressBar.this) {
- final int count = mRefreshData.size();
- for (int i = 0; i < count; i++) {
- final RefreshData rd = mRefreshData.get(i);
- doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
- rd.recycle();
- }
- mRefreshData.clear();
- mRefreshIsPosted = false;
- }
- }
- }
复制代码
所以,其实子线程中还是无法更新UI的,之所以这些控件可以直接更新,都是因为它们自己实现了,把更新操作放到主线程的逻辑。至于上面的文字是否可以这样更改,进入设置文字的方法查看下实现,就知道咯
深圳校区除了全国独有问答网,就业老师面试服务,还有更多神秘惊喜等着你,咨询热线:0755-66689855