AndroidView刷新机制 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

AndroidView刷新机制

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:28


一:总体解释
在Android的构造体系中,父View负责刷新、构造显示子View;而当子View须要刷新时,则是通知父View来完成。
            parent = parent.invalidateChildInParent(location, dirty);
二:代码分析
1).ViewGroup的addView办法,理浇愁数的意义和传递
[img]
invalidate调用父类View的办法
addViewInner办法重要做的工作是
[img]
[img]
view的dispatchAttachedToWindow(AttachInfo info, int visibility)办法
        final boolean isOpaque = child.isOpaque() && !drawAnimation && child.getAnimation() != null;
[img]
  
1).View的invalidate办法,这是一个大年夜下第向上回溯的过程,每一层的父View都将本身的显示区域与传入的刷新 Rect做交集。
void invalidate(boolean invalidateCache) {
        if (ViewDebug.TRACE_HIERARCHY) {
            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
        }
        if (skipInvalidate()) {
            return;
        }
        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
                (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) ||
                (mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
            mPrivateFlags &= ~DRAWN;
            mPrivateFlags |= DIRTY;
                mPrivateFlags |= INVALIDATED;
                mPrivateFlags &= ~DRAWING_CACHE_VALID;
            }
            final AttachInfo ai = mAttachInfo;
            final ViewParent p = mParent;

            //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;
                }

            }
            if (p != null && ai != null) {
                final Rect r = ai.mTmpInvalRect;
                r.set(0, 0, mRight - mLeft, mBottom - mTop);
                // Don't call invalidate -- we don't want to internally scroll
                // our own bounds
                p.invalidateChild(this, r);//调用子类的办法完成

            if (invalidateCache) {
            }
        }
    }

2)ViewGrop的invalidateChild办法

public final void invalidateChild(View child, final Rect dirty) {
   ViewParent parent = this;



    final AttachInfo attachInfo = mAttachInfo;

    if (attachInfo != null) {
        final int[] location = attachInfo.mInvalidateChildLocation;
        // 须要刷新的子View的地位 
          4、调用dispatchDraw ()办法绘制子视图(如不雅该View类型不为ViewGroup,即不包含子视图,不须要重载该 办法)值得解释的是,ViewGroup类已经为我们重写了dispatchDraw ()的功能实现,应用法度榜样一般不须要重写该 办法,但可以重载父类函数实现具体的功能。
        location[CHILD_LEFT_INDEX] = child.mLeft;
        location[CHILD_TOP_INDEX] = child.mTop;




        // ourselves and the parent to make sure the invalidate request goes through
        final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;



        // Check whether the child that requests the invalidate is fully opaque
                } else if (parent instanceof ViewRoot) {
        // Mark the child as dirty, using the appropriate flag
        // Make sure we do not set both flags at the same time
        final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;



            View view = null;
            if (parent instanceof View) {
                view = (View) parent;
            }


            if (drawAnimation) {
                if (view != null) {
                }
            }
            // 根据父View的地位,偏移刷新区域 


                // 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 && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {

                view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
            }

        } while (parent != null);
    }
}
public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
    if ((mPrivateFlags & DRAWN) == DRAWN) {
        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 the child is drawing an animation, we want to copy this flag onto
            //计算实际可刷新区域 
            if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
                location[CHILD_LEFT_INDEX] = left;
                location[CHILD_TOP_INDEX] = top;
                return mParent;
            mLastIsOpaque = isOpaque();
            }
        } else {
            mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
            location[CHILD_LEFT_INDEX] = mLeft;
            location[CHILD_TOP_INDEX] = mTop;
           dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
                        mBottom - location[CHILD_TOP_INDEX]);
                return mParent;
            }
        }

        return null;
}
      mView.draw()开端绘制,draw()办法实现的功能如下:
这个向上回溯的过程直到ViewRoot那边停止,由ViewRoot对这个最终的刷新区域做刷新


ViewRoot.java
                        ((ViewRoot) parent).mIsAnimating = true;
public void invalidateChild(View child, Rect dirty) {
}
由ViewRoot对象的performTraversals()办法调用draw()办法提议绘制该View树,值得留意的是每次提议画图时,并不会从新绘制每个View树的视图,而只会从新绘制那些“须要重绘”的视图,View类内部变量包含了一个标记位DRAWN,当该视图须要重绘时,就会为该View添加该标记位。


调用流程 :
        do {
                        view.mPrivateFlags |= DRAW_ANIMATION;
          1 、绘制该View的背景
          2 、为显示渐变框做一些预备操作(见5,大年夜多半情况下,不须要改渐变框)          
          3、调用onDraw()办法绘制视图本身   (每个View都须要重载该办法,ViewGroup不须要实现该办法)
 
                mPrivateFlags &= ~DRAWING_CACHE_VALID;
  4.1 dispatchDraw()办法内部会遍历每个子视图,调用drawChild()去从新回调每个子视图的draw()办法(留意, 这个 处所“须要重绘”的视图才会调用draw()办法)。值得解释的是,ViewGroup类已经为我们重写了dispatch Draw()的功能实现,应用法度榜样一般不须要重写该办法,但可以重载父类函数实现具体的功能。


相关案例查看更多