天天记录 - Android 使用dmeo和源码分析invalidate流程
来源:互联网 发布:php 10进制转36进制 编辑:程序博客网 时间:2024/04/30 16:42
点击和抬起Button后,总共执行6次以下流程,LOG如下
Button invalidateDrawable(Drawable drawable)Button invalidate , l = 0 , t = 0 , r = 480 , b = 72LinearLayout invalidateChildInParent
从源码查看下Invalidate的执行流程。
从打印出的LOG来看,点击后会先触发Button的invalidate函数,然后调用父控件LinearLayout的invalidate。
1. 从LOG来看会首先调用Button.invalidateDrawable函数,未分析何处调用invalidateDrawable,这里不关心谁最初调用的,仅从invalidateDrawable函数开始分析源码。但是Button中没有invalidateDrawable函数其父类TextView.invalidateDrawable函数源码:
TextView.invalidateDrawable
@Override public void invalidateDrawable(Drawable drawable) { // 验证是否显示Drawable,此方法可以覆写 if (verifyDrawable(drawable)) { // 从drawable获取绘制区域 final Rect dirty = drawable.getBounds(); ...... // 调用View.invalidate重绘指定区域 invalidate(dirty.left + scrollX, dirty.top + scrollY, dirty.right + scrollX, dirty.bottom + scrollY); } }
public void invalidate(int l, int t, int r, int b) { // 如果不显示也不是动画,不会执行刷新 if (skipInvalidate()) { return; } // 执行此分支,并设置mPrivateFlags三个属性 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) { mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; mPrivateFlags |= PFLAG_INVALIDATED; mPrivateFlags |= PFLAG_DIRTY; final ViewParent p = mParent; final AttachInfo ai = mAttachInfo; // 此分支不会被执行 //noinspection PointlessBooleanExpression,ConstantConditions if (!HardwareRenderer.RENDER_DIRTY_REGIONS) { if (p != null && ai != null && ai.mHardwareAccelerated) { // fast-track for GL-enabled applications; just invalidate the whole hierarchy // with a null dirty rect, which tells the ViewAncestor to redraw everything p.invalidateChild(this, null); return; } } // 因为显示的坐标系是x轴从左向右递增 left < right // y轴是从上向下递增 top < bottom if (p != null && ai != null && l < r && t < b) { // 处理滚动后的值 final int scrollX = mScrollX; final int scrollY = mScrollY; final Rect tmpr = ai.mTmpInvalRect; tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY); // 针对当前例子,Button调用的是LinearLayout.invalidateChild p.invalidateChild(this, tmpr); } } }
LinearLayout中没有invalidateChild函数实现,所以在父控件ViewGroup中查找ViewGroup.invalidateChild
ViewGroup.invalidateChild
public final void invalidateChild(View child, final Rect dirty) { ViewParent parent = this; final AttachInfo attachInfo = mAttachInfo; // 值非空,执行此分支 if (attachInfo != null) { // If the child is drawing an animation, we want to copy this flag onto // ourselves and the parent to make sure the invalidate request goes // through final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION; // Check whether the child that requests the invalidate is fully opaque // Views being animated or transformed are not considered opaque because we may // be invalidating their old position and need the parent to paint behind them. Matrix childMatrix = child.getMatrix(); final boolean isOpaque = child.isOpaque() && !drawAnimation && child.getAnimation() == null && childMatrix.isIdentity(); // Mark the child as dirty, using the appropriate flag // Make sure we do not set both flags at the same time int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY; // 不执行此分支 if (child.mLayerType != LAYER_TYPE_NONE) { mPrivateFlags |= PFLAG_INVALIDATED; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; child.mLocalDirtyRect.union(dirty); } final int[] location = attachInfo.mInvalidateChildLocation; location[CHILD_LEFT_INDEX] = child.mLeft; location[CHILD_TOP_INDEX] = child.mTop; // 不执行此分支 if (!childMatrix.isIdentity() || (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { RectF boundingRect = attachInfo.mTmpTransformRect; boundingRect.set(dirty); Matrix transformMatrix; if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { Transformation t = attachInfo.mTmpTransformation; boolean transformed = getChildStaticTransformation(child, t); if (transformed) { transformMatrix = attachInfo.mTmpMatrix; transformMatrix.set(t.getMatrix()); if (!childMatrix.isIdentity()) { transformMatrix.preConcat(childMatrix); } } else { transformMatrix = childMatrix; } } else { transformMatrix = childMatrix; } transformMatrix.mapRect(boundingRect); dirty.set((int) (boundingRect.left - 0.5f),Dirty (int) (boundingRect.top - 0.5f), (int) (boundingRect.right + 0.5f), (int) (boundingRect.bottom + 0.5f)); } do { View view = null; if (parent instanceof View) { view = (View) parent; } // 例子中未使用动画,不执行此分支 if (drawAnimation) { if (view != null) { view.mPrivateFlags |= PFLAG_DRAW_ANIMATION; } else if (parent instanceof ViewRootImpl) { ((ViewRootImpl) parent).mIsAnimating = true; } } // If the parent is dirty opaque or not dirty, mark it dirty with the opaque // flag coming from the child that initiated the invalidate if (view != null) { if ((view.mViewFlags & FADING_EDGE_MASK) != 0 && view.getSolidColor() == 0) { opaqueFlag = PFLAG_DIRTY; } if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) { view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag; } } // 在do-while循环,View树形结构,依次向上遍历。 // 当前Button父控件是LinearLayout parent = parent.invalidateChildInParent(location, dirty); if (view != null) { // Account for transform on current parent Matrix m = view.getMatrix(); if (!m.isIdentity()) { RectF boundingRect = attachInfo.mTmpTransformRect; boundingRect.set(dirty); m.mapRect(boundingRect); dirty.set((int) (boundingRect.left - 0.5f), (int) (boundingRect.top - 0.5f), (int) (boundingRect.right + 0.5f), (int) (boundingRect.bottom + 0.5f)); } } } while (parent != null); // 如果当前View的parent非空再次执行 } }
LinearLayout中不存在invalidateChildInParent,但其父类ViewGroup中包含
ViewGroup.invalidateChildInParent
public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) { // DRAWN 和 DRAWING_CACHE_VALID 开关是否打开 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) { // 没有动画 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) != FLAG_OPTIMIZE_INVALIDATE) { dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX, location[CHILD_TOP_INDEX] - mScrollY); final int left = mLeft; final int top = mTop; if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) { dirty.setEmpty(); } } mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; location[CHILD_LEFT_INDEX] = left; location[CHILD_TOP_INDEX] = top; if (mLayerType != LAYER_TYPE_NONE) { mPrivateFlags |= PFLAG_INVALIDATED; mLocalDirtyRect.union(dirty); } return mParent; } else { // 有动画,所以当前不执行此分支 mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID; location[CHILD_LEFT_INDEX] = mLeft; location[CHILD_TOP_INDEX] = mTop; if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { dirty.set(0, 0, mRight - mLeft, mBottom - mTop); } else { // in case the dirty rect extends outside the bounds of this container dirty.union(0, 0, mRight - mLeft, mBottom - mTop); } if (mLayerType != LAYER_TYPE_NONE) { mPrivateFlags |= PFLAG_INVALIDATED; mLocalDirtyRect.union(dirty); } return mParent; } } return null; }
invalidateChildInParent明天重点介绍
参考资料:
《Android 内核剖析》 第13章 柯元旦
- 天天记录 - Android 使用dmeo和源码分析invalidate流程
- 天天记录 - Android invalidate流程分析-图文
- 天天记录 - Android invalidate流程方法调用堆栈分析
- 天天记录 - Android refreshDrawableState源码及流程简单分析
- 天天记录 - Android invalidate学习使用的例子
- 天天记录 - Android ListView onTouchEvent源码分析
- 天天记录 - Android requestLayout源码简单分析
- 天天记录 - Android addView源码分析
- Android requestLayout和invalidate源码分析
- Android invalidate()源码分析
- Android View 绘制流程 与invalidate 和postInvalidate 分析--从源码角度
- 天天记录 - Windows 使用GIT下载Android Framework源码
- 天天记录 - Android内存分析工具DDMS heap + MAT 安装和使用
- 天天记录 - Android内存分析工具DDMS heap + MAT 安装和使用
- 天天记录 - Android ListView itemType使用Holder原理简单分析
- Android View刷新原理Invalidate()和PostInvalidate()源码分析
- 天天记录 - Andorid Invalidate 引发的思考
- 天天记录 - Android setVisibility参数VISIBLE, GONE, INVISIBLE与源码简单分析
- JAVA缓存的实现(转载)
- C# 获取HTML表单文件上传
- HBase 官方文档中文版
- web-socket-js-master
- JS 时钟倒影
- 天天记录 - Android 使用dmeo和源码分析invalidate流程
- PHP中获取文件扩展名的N种方法
- Software - How Software Companies Die
- C++ Primer 笔记
- Spring mongodb 之简单CRUD
- C++学习感悟
- IT农民工如何来美国工作
- thinkphp + dwz 总结
- 移动云监控