`
nanjingjiangbiao_T
  • 浏览: 2739332 次
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

View的更新原理

 
阅读更多

我知道android的view布局是树形布局的。子View需要刷新的自身界面的时候,把需求告诉父亲,则父View负责刷新、布局显示子View,从上到下。

public void invalidate() {
    final ViewParent p = mParent;
    final AttachInfo ai = mAttachInfo;
    if (p != null && ai != null) {
        final Rect r = ai.mTmpInvalRect;

        // 设置刷新区域为自己的尺寸 
        r.set(0, 0, mRight - mLeft, mBottom - mTop);
        p.invalidateChild(this, r);
    }
}

从上面的代码我们可以看出:子View调用invalidate时,首先找到自己父View(View的成员变量mParent记录自己的父View),然后将AttachInfo中保存的信息告诉父View刷新自己。

View的父子关系的建立分为两种情况:

(1) View加入ViewGroup中

private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) {

         ...

            // tell our children
        if (preventRequestLayout) {
            child.assignParent(this);
        } else {
            child.mParent = this;
        }

       ...

}

2)DecorView注册给WindowManagerImpl时,产生一个ViewRoot作为其父View。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView){

    .....

    view.assignParent(this);

    ....

}

AttachInfo是在View第一次attach到Window时,ViewRoot传给自己的子View的。这个AttachInfo之后,会顺着布局体系一直传递到最底层的View。

View.java

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
    mAttachInfo = info;

    .....
}

ViewGroup.java

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
    super.dispatchAttachedToWindow(info, visibility);

    for (int i = 0; i < count; i++) {
        children[i].dispatchAttachedToWindow(info, visibility);
    }
}

并且在新的View被加入ViewGroup时,也会将该AttachInfo传给加入的View

ViewGroup.java

private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) {

    child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));

}

到这里明白了mParent与AttachInfo代表的意义,可以继续刷新过程的分析。

在invalidate中,调用父View的invalidateChild,这是一个从第向上回溯的过程,每一层的父View都将自己的显示区域与传入的刷新Rect做交集。

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的位置 
        location[CHILD_LEFT_INDEX] = child.mLeft;
        location[CHILD_TOP_INDEX] = child.mTop;

        // 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 & DRAW_ANIMATION) == DRAW_ANIMATION;

        // Check whether the child that requests the invalidate is fully opaque
        final boolean isOpaque = child.isOpaque() && !drawAnimation && child.getAnimation() != null;

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

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

            if (drawAnimation) {
                if (view != null) {
                        view.mPrivateFlags |= DRAW_ANIMATION;
                } else if (parent instanceof ViewRoot) {
                        ((ViewRoot) 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 && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
                view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
            }

            parent = parent.invalidateChildInParent(location, dirty);
        } 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) {

            // 根据父View的位置,偏移刷新区域 
            dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX, location[CHILD_TOP_INDEX] - mScrollY);

            final int left = mLeft;
            final int top = mTop;

            //计算实际可刷新区域 
            if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
                mPrivateFlags &= ~DRAWING_CACHE_VALID;

                location[CHILD_LEFT_INDEX] = left;
                location[CHILD_TOP_INDEX] = top;
                return mParent;
            }
        } 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;
}

这个向上回溯的过程直到ViewRoot那里结束,由ViewRoot对这个最终的刷新区域做刷新。

ViewRoot.java

public void invalidateChild(View child, Rect dirty) {

    scheduleTraversals();

}
分享到:
评论

相关推荐

    基于SYSTEMVIEW通信原理实验报告北邮通信原理实验

    基于SYSTEMVIEW通信原理实验报告北邮通信原理实验

    MATLAB SYSTEM VIEW通信原理实验及系统仿真

    用MATLAB 通信系统仿真,包括模拟调幅,调频,调相,数字编码,数字调制技术等等。内含源码及注释。

    ListView布局之View复用原理举例

    View复用原理是ListView能够流畅滚动并节省系统资源的关键,特别是当列表包含复杂视图时。 首先,我们来理解什么是View复用。在ListView中,屏幕可见的item数量是有限的,当用户滚动时,已滑出屏幕的item会被重新...

    View工作原理

    **View工作原理详解** 在Android开发中,View是构建用户界面的基本元素,它与用户进行交互,接收并处理用户的触摸事件。理解View的工作原理对于优化应用性能和开发自定义视图至关重要。本文将深入探讨View的创建、...

    systemview通信原理实验仿真

    通原实验仿真,共十个,全部可用,基本的模拟和数字调制方法都有,希望对大家有所帮助。

    事务原理MVCC、Readview和行锁原理分析直播中(1).zip

    事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务...

    Beaglebone Black lcd cape 原理图 BB VIEW

    根据提供的信息,我们可以了解到这是一份关于 Beaglebone Black 的 LCD Cape(扩展板)BB View 的原理图文档。为了更好地理解这份文档所涉及的关键技术点,我们先来逐一解析其中包含的信息。 ### 1. 标题:BB VIEW ...

    通信原理System view 仿真实例

    通信原理System view 仿真实例,用System view软件将通信原理教程的各个章节进行了仿真,可以复制通信技术学习

    自定义view基础与原理源码

    本文将深入探讨自定义View的基础与原理,包括它的概念、使用场景以及如何进行自定义。 首先,我们要理解什么是自定义View。在Android系统中,View是构成UI的基本元素,如按钮、文本框等。自定义View则是指开发者...

    通信原理课程设计(SystemView仿真)

    绪论 2 SystemView及其操作简介 3 ...3.1 16QAM系统基本原理 27 3.2 16QAM产生的方法 27 3.3 16QAM信号的解调方法 28 3.4 16QAM的信号空间 29 3.5 16QAM调制系统仿真设计 30 小结 33 附录 34 谢辞 34 参考文献 34

    北邮通信原理实验基于SYSTEMVIEW通信原理实验报告

    北邮通信原理实验基于SYSTEMVIEW通信原理实验报告

    通信原理SystemView仿真实验指导书

    通信原理SystemView仿真实验指导书

    2ASK调幅法原理Systemview实现

    通过SystemView,我们可以直观地理解2ASK调幅法的工作原理,并进行详细的仿真分析。 2ASK调幅的基本过程是将二进制数字序列转换为模拟信号。这个转换过程中,数字信号被映射到两个不同的幅度级别上,例如,0通常...

    【JavaScript源代码】Vue router-view和router-link的实现原理.docx

    `&lt;router-view&gt;` 的实现原理** `&lt;router-view&gt;` 是 Vue Router 中的一个特殊组件,它作为路由的占位符,用于展示匹配当前路由的组件。当路由变化时,`&lt;router-view&gt;` 将被替换为与当前激活路由配置对应的组件实例...

    通信原理课程设计----基于Systemview的通信系统的仿真

    学习Systemview仿真软件,培养学生基本掌握电路设计的基本思路和方法,对需要仿真的通信系统各功能模块的工作原理进行分析。 a.二进制振幅键控(2ASK)系统的设计 b.二进制移频键控(2FSK)系统的设计 c.二进制移...

    通信原理实验五--二进制差分相移键控 DPSK--Systemview仿真.rar

    通信原理实验五--二进制差分相移键控 DPSK--Systemview仿真.rar 资源包括:DPSK的调制、解调和相比较法解调DPSK 实验目的 1、掌握 DPSK 调制和解调的基本原理; 2、掌握 DPSK 数据传输过程,熟悉典型电路; 3、...

    通信原理SystemView 2PSK仿真

    1. **2PSK调制原理**:2PSK采用两种不同的相位,通常为0°和180°,代表二进制的“0”和“1”。通过改变载波信号的相位,我们可以将二进制数据编码到模拟信号中。 2. **数字信号处理**:在2PSK仿真中,首先要进行...

    Android View的工作原理

    PowerPoint演示文稿AndroidView的工作原理WWW1PPTCOMContents一前言二工作流程三measure过程四layout过程五draw过程一前言11ViewView类是用户界

Global site tag (gtag.js) - Google Analytics