Android UI绘制之View重绘

来源:互联网 发布:如何盗取淘宝账号 编辑:程序博客网 时间:2024/05/23 11:49

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

     

                                 图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的建立及刷新流程。
    





0 0
原创粉丝点击