在Android UI 绘制机制之View创建过程介绍了Android应用绘制View的创建过程,本文将介绍图形如何刷新。我们知道Android的UI界面是通过View和ViewGroup分层树进行定义的,如下图所示。一般在View发生改变时对UI进行重绘,本文介绍重绘的过程。

      Android UI绘制之View重绘_第1张图片

                                 图1:Android UI界面结构

       单UI界面上某一个UI变化了,会显示地调用View对象中的invalidate()。这里需要注意的是invalidate只是标记计算脏区,真正的onDraw过程是有UI线程来完成的,下面来分析整个流程。

 1. View需要重绘调用

 public void invalidate() {        invalidate(true);    }
2. child View调用invalidate时,首先找到自己父View(View的成员变量mParent记录自己的父View),然后将AttachInfo中保存的信息告诉父View刷新自己,父View调用invalidateChild函数刷新child View
void invalidate(boolean invalidateCache) {  if (skipInvalidate()) {      return;  }  if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||          (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||          (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {     ... ...      final ViewParent p = mParent; // 获取父类对象      // noinspection PointlessBooleanExpression,ConstantConditions      if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {          if (p != null && ai != null && ai.mHardwareAccelerated) {              p.invalidateChild(this, null);              return;          }      }      if (p != null && ai != null) {          final Rect r = ai.mTmpInvalRect;          r.set(0, 0, mRight - mLeft, mBottom - mTop); // 设置View的尺寸          p.invalidateChild(this, r); // 调用parent对象让parent对象重绘制child      }  }}
3.再看ViewGroup中的invalidateChild方法的实现

public final void invalidateChild(View child, final Rect dirty) {    ... ...    ViewParent parent = this;    final AttachInfo attachInfo = mAttachInfo;    if (attachInfo != null) {       ... ...        if (dirty == null) {           ......            do {                View view = null;                if (parent instanceof View) {                    view = (View) parent;                    if (view.mLayerType != LAYER_TYPE_NONE) {                        view.mLocalDirtyRect.setEmpty();                        if (view.getParent() instanceof View) {                            final View grandParent = (View) view.getParent();                            grandParent.mPrivateFlags |= INVALIDATED;                            grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;                        }                    }                    if ((view.mPrivateFlags & DIRTY_MASK) != 0) {                        // already marked dirty - we're done                        break;                    }                }               ......                           } while (parent != null);        } else {           ......            do {                View view = null;                if (parent instanceof View) {                    view = (View) parent;                    if (view.mLayerType != LAYER_TYPE_NONE &&                            view.getParent() instanceof View) {                        final View grandParent = (View) view.getParent();                        grandParent.mPrivateFlags |= INVALIDATED;                        grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;                    }                }                ......                parent = parent.invalidateChildInParent(location, dirty); //层层刷新               .......            } while (parent != null);        }    }}
       在 Android UI 绘制机制之View创建过程文章中介绍了DocorView是应用的根,DocorView的parent设置成了Viewroot。再来看ViewRoot中的invalidateChildInParent。

public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {        invalidateChild(null, dirty);        return null;    }
public void invalidateChild(View child, Rect dirty) {        checkThread();  //检测是否是UI线程               if (dirty == null) {            // Fast invalidation for GL-enabled applications; GL must redraw everything            invalidate();            return;        }        if (mCurScrollY != 0 || mTranslator != null) {            mTempRect.set(dirty);            dirty = mTempRect;            if (mCurScrollY != 0) {               dirty.offset(0, -mCurScrollY);            }            if (mTranslator != null) {                mTranslator.translateRectInAppWindowToScreen(dirty);            }            if (mAttachInfo.mScalingRequired) {                dirty.inset(-1, -1);            }        }        if (!mDirty.isEmpty() && !mDirty.contains(dirty)) {            mAttachInfo.mSetIgnoreDirtyState = true;            mAttachInfo.mIgnoreDirtyState = true;        }        mDirty.union(dirty);        if (!mWillDrawSoon) {            scheduleTraversals();         }    }
      在ViewRoot 中最后都会调用scheduleTraversals,由scheduleTraversals发送一个DO_TRAVERSAL消息,由ViewRoot线程调用performTraversals函数实现UI绘制。performTraversals比较复杂,这里不再介绍,它最终会调用View的ondraw。本文与 Android UI 绘制机制之View创建过程大致介绍了Android 应用UI窗口View的建立及刷新流程。
    





更多相关文章

  1. Android 使用Vitamio打造自己的万能播放器(3)――本地播放(主界面、
  2. Android用户界面 UI组件--TextView及其子类(二) Button,selector
  3. Android 设置界面修改为Iphone的tab菜单风格
  4. 总结线程交互
  5. Android 线程完全解析
  6. 主线程中Looper的轮询死循环为何没有阻塞主线程?

随机推荐

  1. android 4 高级编程 第一章摘
  2. Android测试系列之一 - 测试分类(节选)
  3. Fuchsia - 简析
  4. 谷歌发布 Android(安卓)2.2:运行速度提高2
  5. Android开发实践:Android交叉编译工具链的
  6. Android面试题(六)--重要
  7. [原]零基础学习SDL开发之在Android使用SD
  8. Android异步加载图像小结(含线程池,缓存方
  9. Android(安卓)文件操作心得体会
  10. Android之布局属性重点