invalidate
流程图:
11764 void More ...invalidate(boolean invalidateCache) {
11765 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
11766 }
void More ...invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
11769 boolean fullInvalidate) {
11770 if (mGhostView != null) {
11771 mGhostView.invalidate(true);
11772 return;
11773 }
11774
11775 if (skipInvalidate()) {
11776 return;
11777 }
11778
11779 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
11780 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
11781 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
11782 || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
11783 if (fullInvalidate) {
11784 mLastIsOpaque = isOpaque();
11785 mPrivateFlags &= ~PFLAG_DRAWN;
11786 }
11787
11788 mPrivateFlags |= PFLAG_DIRTY;
11789
11790 if (invalidateCache) {
11791 mPrivateFlags |= PFLAG_INVALIDATED;
11792 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
11793 }
11794
11795 // Propagate the damage rectangle to the parent view.
11796 final AttachInfo ai = mAttachInfo;
11797 final ViewParent p = mParent;
11798 if (p != null && ai != null && l < r && t < b) {
11799 final Rect damage = ai.mTmpInvalRect;
11800 damage.set(l, t, r, b);
11801 p.invalidateChild(this, damage);
11802 }
11803
11804 // Damage the entire projection receiver, if necessary.
11805 if (mBackground != null && mBackground.isProjected()) {
11806 final View receiver = getProjectionReceiver();
11807 if (receiver != null) {
11808 receiver.damageInParent();
11809 }
11810 }
11811
11812 // Damage the entire IsolatedZVolume receiving this view's shadow.
11813 if (isHardwareAccelerated() && getZ() != 0) {
11814 damageShadowReceiver();
11815 }
11816 }
11817 }
如上面源码所示,View的invalidate会调到invalidateInternal,里面会设置2个标志位PFLAG_INVALIDATED和PFLAG_DRAWING_CACHE_VALID,PFLAG_INVALIDATED置为1,PFLAG_DRAWING_CACHE_VALID置为0. 并且11801行调用invalidateChild()。
ViewGroup中的invalidateChild方法:
public final void More ...invalidateChild(View child, final Rect dirty) {
4609 ViewParent parent = this;
4610
4611 final AttachInfo attachInfo = mAttachInfo;
4612 if (attachInfo != null) {
4613 // If the child is drawing an animation, we want to copy this flag onto
4614 // ourselves and the parent to make sure the invalidate request goes
4615 // through
4616 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
4617 == PFLAG_DRAW_ANIMATION;
4618
4619 // Check whether the child that requests the invalidate is fully opaque
4620 // Views being animated or transformed are not considered opaque because we may
4621 // be invalidating their old position and need the parent to paint behind them.
4622 Matrix childMatrix = child.getMatrix();
4623 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
4624 child.getAnimation() == null && childMatrix.isIdentity();
4625 // Mark the child as dirty, using the appropriate flag
4626 // Make sure we do not set both flags at the same time
4627 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
4628
4629 if (child.mLayerType != LAYER_TYPE_NONE) {
4630 mPrivateFlags |= PFLAG_INVALIDATED;
4631 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
4632 }
4633
4634 final int[] location = attachInfo.mInvalidateChildLocation;
4635 location[CHILD_LEFT_INDEX] = child.mLeft;
4636 location[CHILD_TOP_INDEX] = child.mTop;
4637 if (!childMatrix.isIdentity() ||
4638 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4639 RectF boundingRect = attachInfo.mTmpTransformRect;
4640 boundingRect.set(dirty);
4641 Matrix transformMatrix;
4642 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4643 Transformation t = attachInfo.mTmpTransformation;
4644 boolean transformed = getChildStaticTransformation(child, t);
4645 if (transformed) {
4646 transformMatrix = attachInfo.mTmpMatrix;
4647 transformMatrix.set(t.getMatrix());
4648 if (!childMatrix.isIdentity()) {
4649 transformMatrix.preConcat(childMatrix);
4650 }
4651 } else {
4652 transformMatrix = childMatrix;
4653 }
4654 } else {
4655 transformMatrix = childMatrix;
4656 }
4657 transformMatrix.mapRect(boundingRect);
4658 dirty.set((int) (boundingRect.left - 0.5f),
4659 (int) (boundingRect.top - 0.5f),
4660 (int) (boundingRect.right + 0.5f),
4661 (int) (boundingRect.bottom + 0.5f));
4662 }
4663
4664 do {
4665 View view = null;
4666 if (parent instanceof View) {
4667 view = (View) parent;
4668 }
4669
4670 if (drawAnimation) {
4671 if (view != null) {
4672 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
4673 } else if (parent instanceof ViewRootImpl) {
4674 ((ViewRootImpl) parent).mIsAnimating = true;
4675 }
4676 }
4677
4678 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4679 // flag coming from the child that initiated the invalidate
4680 if (view != null) {
4681 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4682 view.getSolidColor() == 0) {
4683 opaqueFlag = PFLAG_DIRTY;
4684 }
4685 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
4686 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
4687 }
4688 }
4689
4690 parent = parent.invalidateChildInParent(location, dirty);
4691 if (view != null) {
4692 // Account for transform on current parent
4693 Matrix m = view.getMatrix();
4694 if (!m.isIdentity()) {
4695 RectF boundingRect = attachInfo.mTmpTransformRect;
4696 boundingRect.set(dirty);
4697 m.mapRect(boundingRect);
4698 dirty.set((int) (boundingRect.left - 0.5f),
4699 (int) (boundingRect.top - 0.5f),
4700 (int) (boundingRect.right + 0.5f),
4701 (int) (boundingRect.bottom + 0.5f));
4702 }
4703 }
4704 } while (parent != null);
4705 }
4706 }
可以看到invalidateChild内部有个dowhile循环,不停调用父view的invalidateChildInParent,一直到调用ViewRootImpl的invalidateChildInParent。我们看invalidateChild的L21,把PFLAG_DRAWING_CACHE_VALID置为0,在dowhile循环后,当前view的所有父view,父view的父view。。。都会被PFLAG_DRAWING_CACHE_VALID置为0.调用invalidateChildInParent会传进去一个Rect叫dirty,代表子窗口需要刷新的rect,父窗口会根据这个rect和父窗口本身做union,从而得到父窗口需要刷新的rect区域,然后再传给父窗口的父窗口,一直递归直到ViewRootImpl。
908 public ViewParent More ...invalidateChildInParent(int[] location, Rect dirty) {
909 checkThread();
910 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
911
912 if (dirty == null) {
913 invalidate();
914 return null;
915 } else if (dirty.isEmpty() && !mIsAnimating) {
916 return null;
917 }
918
919 if (mCurScrollY != 0 || mTranslator != null) {
920 mTempRect.set(dirty);
921 dirty = mTempRect;
922 if (mCurScrollY != 0) {
923 dirty.offset(0, -mCurScrollY);
924 }
925 if (mTranslator != null) {
926 mTranslator.translateRectInAppWindowToScreen(dirty);
927 }
928 if (mAttachInfo.mScalingRequired) {
929 dirty.inset(-1, -1);
930 }
931 }
932
933 final Rect localDirty = mDirty;
934 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
935 mAttachInfo.mSetIgnoreDirtyState = true;
936 mAttachInfo.mIgnoreDirtyState = true;
937 }
938
939 // Add the new dirty rect to the current one
940 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
941 // Intersect with the bounds of the window to skip
942 // updates that lie outside of the visible region
943 final float appScale = mAttachInfo.mApplicationScale;
944 final boolean intersected = localDirty.intersect(0, 0,
945 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
946 if (!intersected) {
947 localDirty.setEmpty();
948 }
949 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
950 scheduleTraversals();
951 }
952
953 return null;
954 }
再来看ViewRootImpl的invalidateChildInParent,这个ViewRootImpl类的invalidateChildInParent方法直接返回了null,也就是上面ViewGroup中说的,层层上级传递到ViewRootImpl的invalidateChildInParent方法结束了那个do while循环。这里重点是调用scheduleTraversals,scheduleTraversals会通过Handler的Runnable发送一个异步消息,调用doTraversal方法,然后最终调用performTraversals()执行重绘。performTraversals就是整个View数开始绘制的起始调用地方,所以说View调运invalidate方法的实质是层层上传到父级,直到传递到ViewRootImpl后触发了scheduleTraversals方法,然后整个View树开始重新按照View绘制流程进行重绘任务。
requestLayout.
872 public void More ...requestLayout() {
873 if (!mHandlingLayoutInLayoutRequest) {
874 checkThread();
875 mLayoutRequested = true;
876 scheduleTraversals();
877 }
878 }
以上就是ViewRootImpl的requestLayout方法,可以看到mLayoutRequested变true了,然后触发了scheduleTraversals 方法,requestLayout与invalidate的调用过程类似,只是设置的标志位不同,导致View的绘制流程中执行方法不同而已。
我们可以简单的认为mLayoutRequested为true会触发perfomMeasure(内部会调用onMeasure)和performLayout(内部会调用onLayout)。然后在performDraw内部draw的过程中发现mDirty为空,所以onDraw不会被调用,不重绘。
这么看来requestLayout不会导致onDraw调用了?
也不见得,我们知道requestLayout会导致perfomMeasure和performLayout,如果在layout过程中发现l,t,r,b和以前不一样,那就会触发一次invalidate。代码在View的setFrame中,这个会在layout时被调用。
requestLayout是否会导致全部View都触发Layout和measure?
一个view调用了requestLayout,那么他自己与他的父族view都会被设置为PFLAG_FORCE_LAYOUT,我们在看看measure过程,measure的核心代码处必须满足3个条件之一,而他自己与他的父族view都会被设置为PFLAG_FORCE_LAYOUT,所以他们都必然会被重新measure,但是其他的view就不一定了,就看这3个条件是否会满足。
结论是requestLayout会导致部分view重新measure和layout。a的requestLayout必然会导致a,ap…的重新measure,ap的requestLayout必定会导致ap的measure,但不一定会导致a的measure。
tip: 因为onMeasure后会设置了PFLAG_LAYOUT_REQUIRED标志位,这会导致调用onLayout。
总结:
requestLayout()方法会调用measure过程和layout过程,不会调用draw过程,也不会重新绘制任何View包括该调用者本身
invalidate系列方法请求重绘View树(也就是draw方法),在performTraversals方法中,mLayoutRequested为false,所有onMeasure和onLayout都不会被调用。