毎日記録-Androidはdmeoとソースコードを使用してinvalidateプロセスを分析します
10693 ワード
Buttonをクリックして持ち上げた後、全部で6回以下の流れを実行し、LOGは以下の通りである.
Invalidateの実行フローをソースコードから表示します.
印刷されたLOGを見ると、クリックするとButtonのinvalidate関数がトリガーされ、親コントロールLinearLayoutのinvalidateが呼び出されます.
1. LOGから見るとまずButtonが呼び出されます.invalidateDrawable関数は、invalidateDrawableを呼び出す場所を分析していません.ここでは、誰が最初に呼び出されたのかは気にしません.invalidateDrawable関数からソースコードの分析を開始します.しかしButtonにはinvalidateDrawable関数の親TextViewはありません.invalidateDrawable関数ソース:
TextView.invalidateDrawable
View.invalidate
LinearLayoutにはinvalidateChild関数が実装されていないため、親コントロールView GroupでView Groupを検索する.invalidateChild
ViewGroup.invalidateChild
LinearLayoutにはinvalidateChildInParentは存在しませんが、親のViewGroupには
ViewGroup.invalidateChildInParent
invalidateChildInParent明日のポイント紹介
参考資料:
《Android内核剖析》第13章柯元旦
Button invalidateDrawable(Drawable drawable)
Button invalidate , l = 0 , t = 0 , r = 480 , b = 72
LinearLayout 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);
}
}
View.invalidate
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関数が実装されていないため、親コントロールView GroupでView Groupを検索する.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章柯元旦