Android UI结构源码研究

本文主要探讨了作者对Android 4.3版本UI框架的研究成果,包括参考源码、流程分析和个人经验,旨在分享在CSDN上的Android UI framework理解。
摘要由CSDN通过智能技术生成


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 |
源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值