Android UI绘制之View重绘

     在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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值