android经验相关(android4.3)
由于之前工作需要,对Android的UI framework做了些许研究,主要针对Android4.3的源码参考晚上别人的一些流程分析,加上自己打log得出的一些理解和经验。特意放上CSDN。
*************************************************************************************
一、当setVisibility(View.GONE);时,android所执行的measure、layout和draw相关操作。
******************************** measure & layout *******************************
-->View.setFlag()
{
if (changed & GONE) != 0
requestLayout();
}
-->View.requestLayout()
{
//表示本View已经接受了本次requestlayout的请求。
mPrivateFlags |= PFLAG_FORCE_LAYOUT;
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
}
public boolean isLayoutRequested() {
return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
}
-->一层一层递归到最上面ViewRootImpl的requestLayout之后,scheduleTraversals
-->ViewRootImpl.requestLayout()
{
...
//mLayoutRequested为true则表示接受当前requestLayout请求。
mLayoutRequested = true;
scheduleTraversals();
}
-->ViewRootImpl.performTraversals()
{
// mStopped means whether is in the stopped state(no longer be active)
boolean layoutRequested = mLayoutRequested && !mStopped;
if (layoutRequested) {
performMeasure();
}
final boolean didLayout = layoutRequested && !mStopped;
if (didLayout) {
performLayout();
}
}
-->performMeasure & performLayout
-->到达parent(FrameLayout)时候,onMeasure(int, int)
{
if (child.getVisibility() != GONE)
跳过调用本View的measure
}
-->同理parent(FrameLayout),onLayout(boolean,int,int,int,int)
{
if (child.getVisibility() != GONE)
跳过调用本View的layout
}
-->由于本View的meauser和layout没有被调用,也就是从本View开始的View都没有被重新measure和layout
另外,只有layout的时候会mPivateFlags &= ~PFLAG_FORCE_LAYOUT;(也就是完成了之前的layout请求)
此时,(mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;为true,也就是isLayoutRequestd()返回true。
-->此时如果本View的child View继续调用requestLayout的时候,会因为判断if(mParent.isLayoutRequested)返回true而跳过回溯到
ViewRootImpl的请求,因此就等于无法重新measure或者layout
******************************** draw *******************************
/***
drawSoftware ver.
***/
-->setFlag
{
if (changed & GONE) != 0 {
...
mParent.invalidate(true);
/*PFLAG_DRAWN表示该View已经完成draw操作,通常在invalidate判断,如果已经设置了该flag,则证明可以invalidate,并
*把该flag去掉,表示需要重新draw操作。同时在draw操作执行过程中,会把该flag添加上。
*/
mPrivateFlags |= PFLAG_DRAWN
}
if ((changed & VISIBILITY_MASK) != 0) {
...
mParent.invalidate(true);
}
}
--->invalidate(boolean invalidateCache)
{
//不是visibile和没有运行动画中的view要跳过invalidate
if (skipInvalidate()) {
return;
}
// PFLAG_DRAWN表示是否经过draw,PFLAG_HAS_BOUNDS在layout的时候setFrame设置上
if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) {
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
if (p != null && ai != null) {
final Rect r = ai.mTmpInvalRect;
r.set(0, 0, mRight - mLeft, mBottom - mTop);
//调用parent的invalidateChid
//同时把本View的区域作为dirtyRect为参数传入
p.invalidateChild(this, r);
}
}
}
-->ViewGroup.invalidateChild(View, Rect)
{
do {
parent = parent.invalidateChildInParent(location, dirty);
}while(parent != null);
}
-->ViewGroup.invalidateChildInParent(final int[] location, final Rect dirty)
{
//这里对dirtyRect进行操作
//首先进行滑动的位移计算
dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
location[CHILD_TOP_INDEX] - mScrollY);
//如果没有设上FLAG_CLIP_CHILDREN(在initViewGroup默认设上),则把dirtyRect和自己的区域进行并集操作
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
}
final int left = mLeft;
final int top = mTop;
//否则就把dirtyRect和自己的区域进行交集操作,另外,如果发现没有交集,则把当前dirtyRect设为空。
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
dirty.setEmpty();
}
}
}
然后就这样一直计算dirtyRect,回溯到ViewRootImpl.invalidateChildParent(),并把参数传递过去。
-->ViewRootImpl.invalidateChildInParent(int[] location, Rect dirty)
{
//ViewRootImpl则把dirty和自己的dirtyRect进行并集
final Rect localDirty = mDirty;
localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
//如果dirtyRect和自己的View区域存在交集,或者动画过程中,
//同时没有在performTraversals的执行过程中(!mWillDrawSoon),则会调度一次Traversals
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)) {
//调度一次Traversals,让下次执行performTraversals
//注意:这里和requestLayout不同的是,performTraversals一般都要执行performDraw
//但如果没有requestLayout过,则不会执行measure和layout(两者一般都会一起执行)
scheduleTraversals();
}
}
-->ViewRoomImpl.performTraversals()
-->ViewRootImpl.performDraw()
-->ViewRootImpl.draw()
-->ViewRootImpl.drawSoftware(... Rect dirty)
{
...
//把dirtyRect的值传入lockCanvas,通过jni调用返回一个clipRect是dirty的canvas
int left = dirty.left;
int top = dirty.top;
int right = dirty.right;
int bottom = dirty.bottom;
canvas = mSurface.lockCanvas(dirty);
...
//传入mView的draw(),开始了第一个View的draw调用。
mView.draw(canvas);
}
-->View.draw(canvas) (ViewRootImpl的直接孩子是继承FrameLayout的DecorView)
{
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/
...
dispatchDraw(canvas);
...
}
-->ViewGroup.dispatchDraw(canvas)
{
//从这里可见,只有VISIBILE或者在执行动画过程中的View才会被绘制
if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
for (int i = 0; i < count; i++) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
}
}
} else {
for (int i = 0; i < count; i++) {
final View child = children[getChildDrawingOrder(count, i)];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
}
}
}
}
-->ViewGroup.drawChild(canvas, child, drawingTime)
{
child.draw(canvas, this, drawingTime);
}
-->View.draw(canvas, parent, drawingTime)
{
// Sets the flag as early as possible to allow draw() implementations
// to call invalidate() successfully when doing animations
mPrivateFlags |= PFLAG_DRAWN;
if (!concatMatrix &&
(flags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS |