当前位置:网站首页>你所不知道的WMS
你所不知道的WMS
2022-07-28 00:24:00 【AD钙奶-lalala】
前面我们完成了Handler和Binder的学习,可以说基础已经打好了。如果有不理解的同学,可以看看我的Framework专栏的其他文章,这里默认大家都是有这方面基础的了。
我们先来思考一个问题:invalidate会触发其他View的重绘吗?
答案很明显是会,但是为什么会呢?可能很多人就回答不上来了。还是来看系统源码吧!
打开我的sublime Text,搜索invalidate(),出来很多东西,然后右击,Goto definition。
(备注:sublime Text全局搜索 Find->Find Files)
我们最终会找到View的路径:frameworks/base/core/java/android/view/View.java
首先我们来看一下invalidate的英文是什么意思,一开始可能大家都会去猜这应该是刷新的意思,但是实际却是废弃的意思。
step1:
public void invalidate() {
invalidate(true);
}step2:
invalidateCache设置为true表示完全废弃缓存
public void invalidate(boolean invalidateCache) {
invalidateInternal(0, 0, mRight - mLeft,
mBottom - mTop, invalidateCache, true);
}step3:
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
if (mGhostView != null) {
mGhostView.invalidate(true);
return;
}
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
|| (fullInvalidate && isOpaque() != mLastIsOpaque)) {
if (fullInvalidate) {
mLastIsOpaque = isOpaque();
mPrivateFlags &= ~PFLAG_DRAWN;
}
mPrivateFlags |= PFLAG_DIRTY;
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
// Propagate the damage rectangle to the parent view.
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);
}
// Damage the entire projection receiver, if necessary.
if (mBackground != null && mBackground.isProjected()) {
final View receiver = getProjectionReceiver();
if (receiver != null) {
receiver.damageInParent();
}
}
}
}核心代码:
damage.set(l, t, r, b);
p.invalidateChild(this, damage);意思就是把这块区域交给父布局去处理。
step4:
@Deprecated
@Override
public final void invalidateChild(View child, final Rect dirty) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null && attachInfo.mHardwareAccelerated) {
// HW accelerated fast path
onDescendantInvalidated(child, child);
return;
}
ViewParent parent = this;
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) != 0;
// 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;
}
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) Math.floor(boundingRect.left),
(int) Math.floor(boundingRect.top),
(int) Math.ceil(boundingRect.right),
(int) Math.ceil(boundingRect.bottom));
}
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;
}
}
parent = parent.invalidateChildInParent(location, dirty);//1
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) Math.floor(boundingRect.left),
(int) Math.floor(boundingRect.top),
(int) Math.ceil(boundingRect.right),
(int) Math.ceil(boundingRect.bottom));
}
}
} while (parent != null);
}这里面是一个循环,就是如果还有父布局,就一直会调用注释1这个方法。最终会走到decorView。
step5:
这个方法是最上层ViewRootImpl里面的
@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
checkThread();
if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
if (dirty == null) {
invalidate();
return null;
} else if (dirty.isEmpty() && !mIsAnimating) {
return null;
}
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);
}
}
invalidateRectOnScreen(dirty);//1
return null;
}step6:
private void invalidateRectOnScreen(Rect dirty) {
final Rect localDirty = mDirty;
if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
mAttachInfo.mSetIgnoreDirtyState = true;
mAttachInfo.mIgnoreDirtyState = true;
}
// Add the new dirty rect to the current one
localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
// Intersect with the bounds of the window to skip
// updates that lie outside of the visible region
final float appScale = mAttachInfo.mApplicationScale;
final boolean intersected = localDirty.intersect(0, 0,
(int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
if (!intersected) {
localDirty.setEmpty();
}
if (!mWillDrawSoon && (intersected || mIsAnimating)) {
scheduleTraversals();//1
}
}step7:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable//1, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}注意注释1处
step8:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();//1
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
step9:
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();//1
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}step10:
private void performTraversals() {
···
performMeasure(childWidthMeasureSpec,childHeightMeasureSpec);
···
performLayout(lp, mWidth, mHeight);
···
performDraw();
}这个方法代码非常长,是不是似曾相识了!
总结一下:某一个View调用invalidate方法,回逐级向上调用直到ViewRootimpl,然后重新走绘制流程。
相信通过前面的开胃菜已经对View的invalidate有了一定的理解,那么我们再抛出一个问题:Activity如何如window与view进行分工合作的?
我们知道activity是通过window来管理view的,activity是管理生命周期的,view负责具体显示。
未完待续!
边栏推荐
- BGP联邦实验
- Enterprise operation and maintenance practice - using aliyun container image service to pull and build images of overseas GCR and quay warehouses
- 二叉树的遍历和性质
- HCIP第十三天笔记
- 暴雪《暗黑破坏神 4》PS5 / PS4 测试版添加到 PlayStation 数据库
- 实时数仓:美团的实时数仓建设实践
- Mark's story
- Flink's real-time data analysis practice in iFLYTEK AI marketing business
- GBase 8c 快照同步函数
- GBase 8c 备份控制函数(二)
猜你喜欢
随机推荐
记录一次生产死锁
HCIP第十三天笔记
Enterprise operation and maintenance practice - using aliyun container image service to pull and build images of overseas GCR and quay warehouses
Typescript中类的使用
The petrochemical industry is facing the tide of rising prices, and the digital dealer distribution system platform enables dealers and stores
Simplicity for beauty - programming ideas
js 哪些情况不能用 JSON.parse 、JSON.stringify深拷贝及一个更好的深拷贝方法
【面试:并发篇28:volatile】有序性
UE4 unreal ndisplay plug-in easy to use three fold screen details
Linux Installation mysql8.0.29 detailed tutorial
Process data and change the name of data
Modify the request path using the streaming API of gateway
暴雪《暗黑破坏神 4》PS5 / PS4 测试版添加到 PlayStation 数据库
Flink's real-time data analysis practice in iFLYTEK AI marketing business
存储成本降低 80%,有赞数据中台成本治理怎么做的?
Gbase 8C transaction ID and snapshot
How tormenting are weekly and monthly reports? Universal report template recommended collection! (template attached)
数据安全与隐私计算峰会-可证明安全:学习
抓包精灵NetCapture APP抓包教程《齐全》
GBase 8c 服务器信号函数









