黑马程序员技术交流社区

标题: [深圳特色][问答网]为什么在子线程中可以更新ProgressBar? [打印本页]

作者: 深圳黑马程序员    时间: 2015-12-20 17:16
标题: [深圳特色][问答网]为什么在子线程中可以更新ProgressBar?

ProgressBar是开发中用的一个显示进度条的控件。和其他控件不太一样的地方是,更新进度的函数可以在非UI线程调用并且生效。下面深圳问答网的师生来探讨一下这个问题。



学生问题:Android的子线程中不能更新UI,但为什么在子线程中可以更新ProgressBar呢?还有在ProgressBar上显示进度的文字,是不是也可以在子线程中去完成呢?

老师回答:

ProgressBar这些控件之所以可以在子线程中更新,是因为其底层自己实现了把更新UI的操作放到主线程中运行,包装之后,给你的感觉就是,它可以直接在子线程中更新了。
它的设置进度代码:
  1. @android.view.RemotableViewMethod
  2. public synchronized void setProgress(int progress) {
  3.     setProgress(progress, false);
  4. }

  5. @android.view.RemotableViewMethod
  6. synchronized void setProgress(int progress, boolean fromUser) {
  7.     if (mIndeterminate) {
  8.         return;
  9.     }

  10.     if (progress < 0) {
  11.         progress = 0;
  12.     }

  13.     if (progress > mMax) {
  14.         progress = mMax;
  15.     }

  16.     if (progress != mProgress) {
  17.         mProgress = progress;
  18.         refreshProgress(R.id.progress, mProgress, fromUser);
  19.     }
  20. }
复制代码
这是设置进度的方法,中间调用了refreshProgress来设置进度,我们再跟进refreshProgress方法:
  1. private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
  2.     if (mUiThreadId == Thread.currentThread().getId()) {
  3.         doRefreshProgress(id, progress, fromUser, true);
  4.     } else {
  5.         if (mRefreshProgressRunnable == null) {
  6.             mRefreshProgressRunnable = new RefreshProgressRunnable();
  7.         }

  8.         final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
  9.         mRefreshData.add(rd);
  10.         if (mAttached && !mRefreshIsPosted) {
  11.             post(mRefreshProgressRunnable);
  12.             mRefreshIsPosted = true;

  13.     }
  14. }
复制代码

它先判断了一下,当前线程是否是主线程,如果是,则直接更新,如果不是,则用
  1. post(mRefreshProgressRunnable);
复制代码
的方法,把更新进度的方法扔到主线程执行。
  1. private class RefreshProgressRunnable implements Runnable {
  2.     public void run() {
  3.         synchronized (ProgressBar.this) {
  4.             final int count = mRefreshData.size();
  5.             for (int i = 0; i < count; i++) {
  6.                 final RefreshData rd = mRefreshData.get(i);
  7.                 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
  8.                 rd.recycle();
  9.             }
  10.             mRefreshData.clear();
  11.             mRefreshIsPosted = false;
  12.         }
  13.     }
  14. }
复制代码

所以,其实子线程中还是无法更新UI的,之所以这些控件可以直接更新,都是因为它们自己实现了,把更新操作放到主线程的逻辑。
至于上面的文字是否可以这样更改,进入设置文字的方法查看下实现,就知道咯

[深圳特色] 揭秘内部问答网中经典问题,每周更新!
深圳校区除了全国独有问答网,就业老师面试服务,还有更多神秘惊喜等着你,咨询热线:0755-66689855


作者: cj286    时间: 2015-12-25 23:27
是不是内部封装了啊,就直接可以在主线程中调用啊




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2