View 的工作原理

初识 ViewRoot 和 DecorView

ViewRoot 对应于 ViewRootImpl 类,它是连接 WindowManager 和 DecorView 的纽带,View 的绘制流程通过 ViewRoot 来完成,在 ActivityThread 中,Activity 创建完毕后,会将 DecorView 添加到 Window中,同时会创建 ViewRootImpl 对象,并和 DecorView 建立关联。

View 的绘制流程是从 ViewRoot 的 performTraversals 方法开始,它经过 measure 用来测量 View 的宽和高,layout 来确定 View 在父容器中的放置位置,而 draw 则负责将 View 绘制在屏幕上。

理解 MeasureSpec

  • MeasureSpec 代表一个32位 int 值,高 2 位代表 SpecMode 测量模式,低 30 位代表 SpecSize 某种测试模式下的规格大小。
  • SpecMode 有三类
    1. UNSPECIFIED 父容器不对 View 有任何限制,要多大给多大,一般用于系统内部,表示一种测量状态。
    2. EXACTLY 父容器检测出 View 的精确大小,大小是 SpecSize 指定的值,对应于 LayoutParams 中的 match_parent 和具体数值两种模式。
    3. AT_MOST 父容器指定一个可用大小即 SpecSize ,View 的大小不能大于这个值,对应于LayoutParams 中的 wrap_content。
  • 对于顶级 View(DecorView),其MeasureSpec由窗口尺寸和自身LayoutParams共同决定。
  • 对于普通 View ,其MeasureSpec有父容器的 MeasureSpec 和自身的LayoutParams 共同决定。
普通 View 的 MeasureSpec 的创建规则
LayoutParams\parentSpecModeEXACTLYAT_MOSTUNSPECIFIED
dp/pxEXACTLY(childSize)EXACTLY(childSize)EXACTLY(childSize)
match_parentEXACTLY(parentSize)AT_MOST(parentSize)UNSPECIFIED(0)
wrap_contentAT_MOST(parentSize)AT_MOST(parentSize)UNSPECIFIED(0)

总结
1. 当 View 采用固定宽高的时候,不管父容器的 SpecMode 是什么,View 的MeasureSpec 都是精确模式,大小遵循LayoutParams中的大小。
2. 当 View 宽高是 match_parent 时,如果父容器 SpecMode 是精确模式,那么 View 也是精确模式,大小是父容器的剩余的空间大小。如果父容器 SepcMode 是最大模式,那么 View 也是最大模式,大小不会超过父容器的剩余空间。
3. 当 View 宽高wrap_content 时,不管父容器的 SpecMode 是什么,View 的MeasureSpec 都是最大模式,大小不能超过父容器的剩余空间。

View 的测量过程

  • View 的 measure 的过程由ViewGroup 的 measureChildWithMargins 方法
protected void measureChildWithMargins(View child,
            int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
  • 调用子元素的 measure 方法之前会通过 getChildMeasureSpec 方法得到子元素的MeasureSpec,与父容器的 MeasureSpec 和自身的 LayoutParams 有关。
  • ViewGroup 中的 child.measure 方法,是调用的 View 的 measure 方法,再调用 onMeasure 方法进行测量。

View 的工作流程

  • View 的 measure 过程是由 measure 方法完成,是一个 final 类型的方法,不能有子类重写,measure 方法中会调用 onMeasure 方法,方法如下:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
        getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    } 

protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }

public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

只需要看 SpecMode 的 EXACTLY 和 AT_MOST 两种情况,返回的大小是SpecSize ,是 View 测量后的大小。
getSuggestedMinimumWidth 方法,如果 View 没有设置背景,那么用 minWith 属性所指定的值,如果有背景,取两者之间的最大值。

  • 直接继承 View 的自定义控件,需要重写 onMeasure 方法,并设置 wrap_content 时的大小,否则相当于使用了match_parent,因为使用 wrap_content 时 SpecMode 是AT_MOST,根据查表这种情况下的 SpecSize 是 parentSize ,解决方式如下:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int withSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST && heightMeasureSpec == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mWidth,mHeight);
        } else if (widthMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mWidth,heightSize);
        } else if (heightMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(withSize,mHeight);
        }
    }
数据中心机房是现代信息技术的核心设施,它承载着企业的重要数据和服务,因此,其基础设计与规划至关重要。在制定这样的方案时,需要考虑的因素繁多,包括但不限于以下几点: 1. **容量规划**:必须根据业务需求预测未来几年的数据处理和存储需求,合理规划机房的规模和设备容量。这涉及到服务器的数量、存储设备的容量以及网络带宽的需求等。 2. **电力供应**:数据中心是能源消耗大户,因此电力供应设计是关键。要考虑不间断电源(UPS)、备用发电机的容量,以及高效节能的电力分配系统,确保电力的稳定供应并降低能耗。 3. **冷却系统**:由于设备密集运行,散热问题不容忽视。合理的空调布局和冷却系统设计可以有效控制机房温度,避免设备过热引发故障。 4. **物理安全**:包括防火、防盗、防震、防潮等措施。需要设计防火分区、安装烟雾探测和自动灭火系统,设置访问控制系统,确保只有授权人员能进入。 5. **网络架构**:规划高速、稳定、冗余的网络架构,考虑使用光纤、以太网等技术,构建层次化网络,保证数据传输的高效性和安全性。 6. **运维管理**:设计易于管理和维护的IT基础设施,例如模块化设计便于扩展,集中监控系统可以实时查看设备状态,及时发现并解决问题。 7. **绿色数据中心**:随着环保意识的提升,绿色数据中心成为趋势。采用节能设备,利用自然冷源,以及优化能源管理策略,实现低能耗和低碳排放。 8. **灾难恢复**:考虑备份和恢复策略,建立异地灾备中心,确保在主数据中心发生故障时,业务能够快速恢复。 9. **法规遵从**:需遵循国家和地区的相关法律法规,如信息安全、数据保护和环境保护等,确保数据中心的合法运营。 10. **扩展性**:设计时应考虑到未来的业务发展和技术进步,保证机房有充足的扩展空间和升级能力。 技术创新在数据中心机房基础设计及规划方案中扮演了重要角色。例如,采用虚拟化技术可以提高硬件资源利用率,软件定义网络(SDN)提供更灵活的网络管理,人工智能和机器学习则有助于优化能源管理和故障预测。 总结来说,一个完整且高效的数据中心机房设计及规划方案,不仅需要满足当前的技术需求和业务目标,还需要具备前瞻性和可持续性,以适应快速变化的IT环境和未来可能的技术革新。同时,也要注重经济效益,平衡投资成本与长期运营成本,实现数据中心的高效、安全和绿色运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值