基础知识
1、标志位:
invalidate
方法里面用了大量的标志位去标识各种操作,如果不搞明白这些操作的含义,很容易误解的mPrivateFlags & PFLAG_DIRTY != 0 //mPrivateFlags包含PFLAG_DIRTY这个标志位 mPrivateFlags & PFLAG_DIRTY == PFLAG_DIRTY //同上 mPrivateFlags |= PFLAG_DIRTY //添加PFLAG_DIRTY标志位 mPrivateFlags &= ~PFLAG_DIRTY //移除PFLAG_DIRTY标志位
/** {@hide} */
static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000;
代表drawingCache缓存是否有效。
关于drawingCache: 注意:在Android Q版本已经被标记为@Deprecated,谷歌更推荐自己去创建Bitmap
View组件显示的内容可以通过cache机制保存为bitmap,只需要通过以下API
:void setDrawingCacheEnabled(boolean flag),//开启缓存 Bitmap getDrawingCache(boolean autoScale),//获取缓存图片 void buildDrawingCache(boolean autoScale),//重建缓存 void destroyDrawingCache()//销毁缓存
/**
* Indicates that this view was specifically invalidated, not just dirtied because some
* child view was invalidated. The flag is used to determine when we need to recreate
* a view's display list (as opposed to just returning a reference to its existing
* display list).
*
* @hide
*/
static final int PFLAG_INVALIDATED = 0x80000000;
mPrivateFlags
添加此标志位则表明视图已明确无效,也就是该被重新绘制了,这个标志位用来控制变量mRecreateDisplayList
/** {@hide} */
static final int PFLAG_DRAWN = 0x00000020;
draw
的过去分词,代表这个view
是否已经被绘制完成,在draw
方法被添加
/** {@hide} */
static final int PFLAG_HAS_BOUNDS = 0x00000010;
这个标志位在
layout
过程中被添加,它代表了这个View是否layout过
/**
* View flag indicating whether this view was invalidated (fully or partially.)
*
* @hide
*/
static final int PFLAG_DIRTY = 0x00200000;
代表
这部分视图已经无效
,子View
在View.invalidateInternal
方法里面被添加,父View
在硬件绘制onDescendantInvalidated
中添加
/**
* Mask for {@link #PFLAG_DIRTY}.
*
* @hide
*/
static final int PFLAG_DIRTY_MASK = 0x00200000;
这是
PFLAG_DIRTY
的掩码,我们可以直接理解为它就是PFLAG_DIRTY
,因为它们的值是相同的
关于掩码:
简单来说掩码可以辅助我们判断mPrivateFlag
是否同时满足多个条件,例如我们定义一个掩码:PFLAG_TEST
,用来代表是否同时满足AB
两个条件,这样我们下次需要判断是否同时满足AB
时,就可以直接判断该掩码,而不用去判断A
再判断B
具体可以看这篇文章: 位运算的那些事(三)位掩码↵
然而这里并没有用作多个操作的掩码,或许只是为了拓展,又或者是为了兼容之前的标志位
PFLAG_DIRTY_OPAQUE
?
/** {@hide} */
static final int PFLAG_FORCE_LAYOUT = 0x00001000;
这个标志位在方法
requestLayout
中会被添加,代表强行回调onMeasure
,而不是使用缓存mMeasureCache
/** {@hide} */
static final int PFLAG_HAS_BOUNDS = 0x00000010;
这个标志位在
layout
过程中被添加,它代表了这个View是否layout过
2、变量
/**
* Flag to indicate that this view was marked INVALIDATED, or had its display list
* invalidated, prior to the current drawing iteration. If true, the view must re-draw
* its display list. This flag, used only when hw accelerated, allows us to clear the
* flag while retaining this information until it's needed (at getDisplayList() time and
* in drawChild(), when we decide to draw a view's children's display lists into our own).
*
* {@hide}
*/
@UnsupportedAppUsage
boolean mRecreateDisplayList = false;
根据是否开启硬件加速,
draw
分为:
mAttachInfo.mThreadedRenderer.draw
drawSoftware
这个变量在
硬件加速绘制
过程中使用,当为true
就代表这个View
需要重新绘制
源码
1、invalidate
1.1、View # invalidate
/**
*
* @param invalidateCache Whether the drawing cache for this view should be
* invalidated as well. This is usually true for a full
* invalidate, but may be set to false if the View's contents or
* dimensions have not changed.
* @hide
*/
@UnsupportedAppUsage
//invalidateCache参数代表了drawing chche是否也要跟着刷新,通常情况下都是true
//但是View的内容和尺寸都没有改变的话,传false性能会更好
public void invalidate(boolean invalidateCache) {
invalidateInternal(0, 0, mRight - mLeft, mBottom -
mTop, invalidateCache, true);
}
2、View # invalidateInternal
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
//同时满足以下三个条件就会跳过invalidate
//1、View不可见
//2、而且View没有设置动画
//3、parent不是ViewGroup或者parent不处于过渡态(从VISIBLE、INVISBLE、GONE几个状态里面转换)
if (skipInvalidate()) {
return;
}
//这里判断是否需要将PFLAG_DRAWN去掉,PFLAG_DRAWN代表绘制完成
//这里也就是判断是否需要重新绘制
//只要满足以下条件之一:
//1、View已经初始化绘制完成(调用过draw)并且已经Layout过了
//2、invalidateCache为true 同时 drawingCache有效(绘制缓存有效)
//3、mPrivateFlag没有添加PFLAG_INVALIDATED,即没有重绘过
//4、fullInvalidate为true同时不透明度变化了
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();
//去掉PFLAG_DRAWN标志位
mPrivateFlags &= ~PFLAG_DRAWN;
}
//添加PFLAG_DIRTY标志位
mPrivateFlags |= PFLAG_DIRTY;
//【分析点1】
//如果invalidateCache为true,通常情况下我们调用invalidate()时
//invalidateCache都会为true
//1、添加PFLAG_INVALIDATED标志位
//2、去除PFLAG_DRAWING_CACHE_VALID标志位
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
//【分析点2】
//1、从AttachInfo里面得到一块dirty区域,这块区域就是需要刷新的
//2、如果ViewParent !=null,调用ViewParent的invalidateChild,这也就是为什么在主线程
//的onCreate刷新UI并不会因为ViewRootImpl不存在而报错,因为p==null
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);
}
...
}
}
3、ViewGroup # invalidateChild
//注意注解@Deprecated
@Deprecated
@Override
public final void invalidateChild(View child, final Rect dirty) {
final AttachInfo attachInfo = mAttachInfo;
//==============分支1====================//
//【分析点3】
//如果开了硬件加速的话,是直接调用onDescendantInvalidated
//和软件绘制一样,也是不断向上调用,直到调用ViewRootImpl
if (attachInfo != null && attachInfo.mHardwareAccelerated) {
// HW accelerated fast path
onDescendantInvalidated(child, child);
return;
}
//==============分支2====================//
//【分析点4】
//没有开启硬件加速的逻辑
ViewParent parent = this;
if (attachInfo != null) {
//【分析点5】
//要注意,开启了硬件加速是不会走这里的!!
//设置了layerType并不代表开启了硬件加速,它们直接没有直接关系的(但是有联系)
//可以理解为:view可以被绘制到off-screen buffers(离屏缓冲区),layer就是一个buffer
//layerType分成三种:
//1、LAYER_TYPE_HARDWARE
//2、LAYER_TYPE_SOFTWARE
//3、LAYER_TYPE_NONE
//默认的layerType为LAYER_TYPE_NONE
//所以这里是设置了layerType的情况下,才会做以下两件事:
//1、为当前ViewGroup添加PFLAG_INVALIDATED标志位
//2、清除PFLAG_DRAWING_CACHE_VALID标志位
if (child.mLayerType != LAYER_TYPE_NONE) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
//省略设置dirty区域大小的代码
...
do {
View view = null;
if (parent instanceof View) {
view = (View) parent;
}
...
//【分析点6】
//通过do-while不断调用invalidateChildInParent
//直到ViewRootImpl
parent = parent.invalidateChildInParent(location, dirty);
...
} while (parent != null);
}
}
分支1:开启硬件加速
1、ViewGroup # onDescendantInvalidated
@Override