深入探讨 Android 的 View 显示过程与源码分析

文章目录

    • 1. 探讨 Android 的 View 显示过程
      • 1.1. `onFinishInflate`
      • 1.2. `onAttachedToWindow`
      • 1.3. `onMeasure`
      • 1.4. `onSizeChanged`
      • 1.5. `onLayout`
      • 1.6. `onDraw`
    • 2. 系统代码分析
      • 1.1. `onFinishInflate`
      • 1.2. `onAttachedToWindow`
      • 1.3. `onMeasure`
      • 1.4. `onSizeChanged`
      • 1.5. `onLayout`
      • 1.6. `onDraw`
    • 3. 视图显示过程总结
    • 4. 优化和性能考虑
    • 5. 结论
    • 6. 进一步深入探讨 Android 的 View 显示过程
      • 6.1. `onFinishInflate`
      • 6.2. `onAttachedToWindow`
      • 6.3. `onMeasure`
      • 6.4. `onSizeChanged`
      • 6.5. `onLayout`
      • 6.6. `onDraw`
    • 7. 视图显示过程总结(续)

1. 探讨 Android 的 View 显示过程

在 Android 中,View 的显示过程涉及多个步骤和方法,从底层到上层依次执行。理解这些步骤和方法对优化 UI 性能和实现复杂的自定义 View 非常重要。

1.1. onFinishInflate

当一个 View 从 XML 布局文件中被加载并完成所有子 View 的初始化时,onFinishInflate 方法被调用。这个方法在整个布局层次结构被完全创建之后调用,可以在这里进行一些额外的初始化工作。

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    // 视图和子视图的初始化工作
}

1.2. onAttachedToWindow

当一个 View 被附加到一个窗口时,onAttachedToWindow 方法被调用。在这个方法中,可以进行一些与窗口相关的初始化工作,例如启动动画、设置监听器等。

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    // 视图附加到窗口后的操作
}

1.3. onMeasure

onMeasure 方法用于测量 View 的大小。这个方法在布局过程中多次调用,用于确定每个 View 的宽度和高度。自定义 View 时,通常需要重写这个方法以处理特定的测量需求。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    setMeasuredDimension(width, height);
}

1.4. onSizeChanged

当 View 的大小发生变化时,onSizeChanged 方法被调用。这通常发生在 View 的初次布局和大小调整时。在这个方法中,可以根据新的大小进行调整。

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    // 视图大小改变后的操作
}

1.5. onLayout

onLayout 方法用于为 View 的所有子 View 安置位置。这个方法在布局过程中调用,用于确定子 View 的位置。

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    // 布局子视图的位置
    int childLeft = 0;
    int childTop = 0;
    for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight());
        childTop += child.getMeasuredHeight();
    }
}

1.6. onDraw

onDraw 方法用于绘制 View 的内容。在这个方法中,可以使用 Canvas 对象进行绘制操作,例如绘制文本、图形等。自定义 View 时,通常需要重写这个方法以实现特定的绘制需求。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 自定义绘制操作
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
}

2. 系统代码分析

1.1. onFinishInflate

ViewGroup 类中,当所有的子 View 都被加载并添加到父 View 时,onFinishInflate 方法被调用。它确保了布局的完整性和一致性。

1.2. onAttachedToWindow

onAttachedToWindow 方法在 View 的 ViewRootImpl 被创建并与窗口关联时调用。它确保 View 可以访问窗口相关的资源和服务。

1.3. onMeasure

onMeasure 方法是 View 类中的一个核心方法,它通过 MeasureSpec 参数来计算 View 的大小。MeasureSpec 包含测量模式和尺寸信息。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    // 自定义测量逻辑
}

1.4. onSizeChanged

onSizeChanged 方法在 View 类中实现,用于处理 View 大小的变化。它提供了新旧尺寸的信息,以便在大小变化时进行相应的调整。

1.5. onLayout

onLayout 方法在 ViewGroup 类中实现,用于布置子 View 的位置。它通过遍历子 View 并调用每个子 View 的 layout 方法来实现布局。

1.6. onDraw

onDraw 方法在 View 类中实现,用于绘制 View 的内容。Canvas 对象提供了一系列绘制方法,可以在 onDraw 方法中调用这些方法进行自定义绘制。

3. 视图显示过程总结

  1. 视图加载和初始化

    • XML 布局文件被解析并创建 View 实例。
    • onFinishInflate 方法被调用,完成视图和子视图的初始化。
  2. 视图附加到窗口

    • 当 View 被添加到窗口时,onAttachedToWindow 方法被调用。
    • 可以在此方法中进行与窗口相关的初始化工作。
  3. 测量视图

    • 在布局过程中,onMeasure 方法被调用,用于测量 View 的大小。
    • 通过 MeasureSpec 参数来确定 View 的测量模式和尺寸。
  4. 视图大小变化

    • 当 View 的大小发生变化时,onSizeChanged 方法被调用。
    • 可以在此方法中根据新的大小进行调整。
  5. 布局子视图

    • 在布局过程中,onLayout 方法被调用,用于布置子 View 的位置。
    • 通过遍历子 View 并调用每个子 View 的 layout 方法来实现布局。
  6. 绘制视图

    • 在绘制过程中,onDraw 方法被调用,用于绘制 View 的内容。
    • 可以在 onDraw 方法中使用 Canvas 对象进行自定义绘制。

4. 优化和性能考虑

  • 视图层次结构优化:避免过深的视图层次结构,尽量减少布局嵌套。
  • 异步任务:避免在主线程中执行耗时操作,使用异步任务处理。
  • 内存管理:及时释放不再需要的资源,避免内存泄漏。

5. 结论

通过深入理解和合理使用 Android 中的 View 显示过程,可以构建出高效、稳定且用户体验良好的应用程序。掌握这些关键技术和设计模式,不仅可以提高开发效率,还能显著提升应用的整体质量。在实际开发中,灵活应用这些技术,结合实际需求进行优化和调整,是构建优秀 Android 应用的基础。

6. 进一步深入探讨 Android 的 View 显示过程

为了更好地理解 Android View 的显示过程,我们需要深入分析系统源码中的具体实现。以下是一些关键方法在系统源码中的详细说明。

6.1. onFinishInflate

ViewGroup.java 中,onFinishInflate 方法的定义如下:

protected void onFinishInflate() {
    // This is called after a view and all of its children has been inflated
}

这个方法被调用时,整个布局树已经被完全构建,可以在此处进行一些额外的初始化工作。

6.2. onAttachedToWindow

View.java 中,onAttachedToWindow 方法的定义如下:

protected void onAttachedToWindow() {
    mAttachInfo = mParent.getViewRootImpl().mAttachInfo;
    if (mOverlay != null) {
        mOverlay.getOverlayView().dispatchAttachedToWindow(mAttachInfo, mWindowAttachCount);
    }
    onVisibilityAggregated(isAggregatedVisible());
    if ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) != 0) {
        refreshDrawableState();
    }
    // Additional operations when the view is attached to the window
}

这个方法确保了 View 能够访问与窗口相关的资源和服务。

6.3. onMeasure

onMeasure 方法在 View.java 中的实现如下:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    // Measure the view dimensions
    int width;
    int height;

    if (widthMode == MeasureSpec.EXACTLY) {
        width = widthSize;
    } else {
        // Measure the width based on the content and padding
        width = computeWidth();
    }

    if (heightMode == MeasureSpec.EXACTLY) {
        height = heightSize;
    } else {
        // Measure the height based on the content and padding
        height = computeHeight();
    }

    setMeasuredDimension(width, height);
}

onMeasure 方法通过 MeasureSpec 参数确定 View 的测量模式和尺寸。

6.4. onSizeChanged

onSizeChanged 方法在 View.java 中的实现如下:

protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    // Handle the size change
    if (w != oldw || h != oldh) {
        // Perform any operations needed when the size changes
    }
}

这个方法提供了新旧尺寸的信息,以便在大小变化时进行相应的调整。

6.5. onLayout

onLayout 方法在 ViewGroup.java 中的实现如下:

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    int count = getChildCount();
    for (int i = 0; i < count; i++) {
        View child = getChildAt(i);
        if (child.getVisibility() != GONE) {
            int childLeft = // Calculate the child's left position
            int childTop = // Calculate the child's top position
            child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight());
        }
    }
}

onLayout 方法遍历子 View 并调用每个子 View 的 layout 方法来实现布局。

6.6. onDraw

onDraw 方法在 View.java 中的实现如下:

protected void onDraw(Canvas canvas) {
    // Perform custom drawing operations
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
}

onDraw 方法使用 Canvas 对象进行自定义绘制。

7. 视图显示过程总结(续)

  1. 视图加载和初始化

    • 解析 XML 布局文件并创建 View 实例。
    • 调用 onFinishInflate 方法,完成视图和子视图的初始化。
  2. 视图附加到窗口

    • View 被添加到窗口时调用 onAttachedToWindow 方法。
    • 进行与窗口相关的初始化工作。
  3. 测量视图

    • 布局过程中调用 onMeasure 方法测量 View 的大小。
    • 使用 MeasureSpec 参数确定测量模式和尺寸。
  4. 视图大小变化

    • View 大小变化时调用 onSizeChanged 方法。
    • 根据新的大小进行调整。
  5. 布局子视图

    • 布局过程中调用 onLayout 方法布置子 View 的位置。
    • 遍历子 View 并调用每个子 View 的 layout 方法实现布局。
  6. 绘制视图

    • 绘制过程中调用 onDraw 方法绘制 View 的内容。
    • 使用 Canvas 对象进行自定义绘制。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/663445.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python网页处理与爬虫实战:使用Requests库进行网页数据抓取

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

LDR6328Q:重塑Type-C接口取电体验的新星

在当今日益发展的电子设备市场中&#xff0c;快速、高效的电源管理成为了众多厂商和消费者关注的焦点。LDR6328Q作为一款专为设备端设计的Type-C接口取电芯片&#xff0c;凭借其独特的功能和优势&#xff0c;正在逐步改变我们的电源管理方式。 一、LDR6328Q的核心特点 多协议…

高磷废酸除铝除铁再生技术的实际应用

在化工和金属加工行业中&#xff0c;高磷废酸的处理和再生是一个重要的环保和经济效益问题。废酸中通常含有铝、铁等杂质&#xff0c;这些杂质不仅影响废酸的再利用价值&#xff0c;还可能对环境造成污染。因此&#xff0c;开发高效的高磷废酸除铝除铁再生技术具有重要的实际意…

[排序算法]插入排序+希尔排序全梳理!

目录 1.排序是什么&#xff1f;1.1排序的概念1.2排序运用1.3常见的排序算法 2.插入排序分类3.直接插入排序基本思想具体步骤&#xff1a;动图演示代码实现直接插入排序的特性总结&#xff1a; 4. 希尔排序基本思想具体步骤动图演示代码实现希尔排序的特性总结&#xff1a; 5.总…

阿里云CDN流量被盗刷或CC攻击会怎么样?

最近&#xff0c;一位使用了阿里云CDN的站长向主机吧反应&#xff0c;其域名使用的阿里云CDN不知道是因为被盗刷还是被CC攻击&#xff0c;导致不仅原本帐号上的3T流量包用完了&#xff0c;连帐户也欠了几百元的流量费。 而产生这么多流量的只是晚上睡一觉起来&#xff0c;手机…

全志H616 通过Cedrus和v4l2_request API实现硬件编解码加速(香橙派zero2)

编译安装或加载cedrus驱动模块&#xff0c;加载v4l2-mem2mem Sunxi-Cedrus 致力于为全志 SoC 提供硬件加速的视频解码和编码支持&#xff0c;并将其引入主线 Linux 内核。此外&#xff0c;还为典型的基于 GNU/Linux 的系统提供了与内核驱动程序接口的其他用户空间组件。 Sunx…

调节效应多元统计回归

什么是调节效应&#xff0c;给个例子说明一下: 背景 假设我们有一个国家的经济数据&#xff0c;我们希望研究产业数字化是否调节了环境规制对产业结构调整的影响。 步骤 1. 假设检验 原假设 (H0)&#xff1a; 产业数字化对环境规制与产业结构调整之间的关系没有调节作用。…

浏览器提示413 Request Entity Too Large

1 问题 2 解决 2.1 后端java配置 2.2 Nginx配置

【Git篇 二】idea中使用git合并分支(拉取分支)

idea中使用git合并分支 前言idea使用git合并分支1) 将主分支&#xff08;master&#xff09;更新到自己的分支&#xff08;dev&#xff09;① checkout到自己分支② 目标分支&#xff08;dev&#xff09;更新到当前分支&#xff08;dev_KC240524&#xff09;③ 当前分支出现“绿…

提升B端图表设计技能:教程分享

图表是数据可视化的常用表现形式&#xff0c;是对数据的二次加工&#xff0c;可以帮助我们理解数据、洞悉数据背后的真相&#xff0c;让我们更好地适应这个数据驱动的世界。本期就来带大家学习图表的设计及构成&#xff0c;帮助大家更好的理解图表设计。 设计教程源文件http:/…

Keras深度学习框架实战(1):图像分类识别

1、绪论 1.1 图像分类的定义 图像分类是计算机视觉领域中的一项基本任务&#xff0c;其定义是将输入图像分配给预定义类别中的一个或多个。具体来说&#xff0c;图像分类系统接受一个图像作为输入&#xff0c;并输出一个或多个类别标签&#xff0c;这些标签描述了图像中的内容…

华为设备RIP基础路由实验

华为设备RIP基础路由实验 实验拓扑&#xff1a; RIP&#xff1a;距离矢量的动态路由&#xff0c;路由通信有方向&#xff0c;度量值metric取值范围&#xff08;1-16&#xff09;16表示目标主机不可达。 路由的版本分为&#xff1a;RIPV1&#xff08;广播通信目标地址是255.255…

Mysql树形结构递归查询

Mysql树形结构递归查询 1.表的基础数据2.基础查询语句3.Mysql8递归查询 1.表的基础数据 类似于这种三级目录&#xff1a; – 1&#xff1a;根结点 – 1-1至1-11 – 1-1-1 至1-1-10 2.基础查询语句 可以使用内联查询inner join去查询&#xff1a; SELECTone.id o…

如何做好流程优化?看这里的目的、原则和方法

流程管理的本质是通过构造卓越的业务流程让流程增值&#xff0c;为客户创造真正的价值。 但卓越的业务流程并不是一蹴而就的&#xff0c;有一个过程&#xff0c;这个过程就是业务流程和流程管理体系不断优化提升的过程&#xff08;可以参照流程成熟度评价模型&#xff09;。 …

React组件通信——兄弟组件

兄弟组件通信 方法一&#xff1a;状态提升 子组件先将数据传递到父组件&#xff0c;父组件再把数据传到另一个子组件中。 import { useState } from "react"; // 定义A组件&#xff0c;向B组件发送数据 function A({ onGetMsg }) {const name "this is A na…

【机器学习】Adaboost: 强化弱学习器的自适应提升方法

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Adaboost: 强化弱学习器的自适应提升方法引言Adaboost基础概念弱学习器与强学习…

跨境经营的艺术:中资企业海外市场售后服务创新与挑战

出海&#xff0c;已不再是企业的“备胎”&#xff0c;而是必须面对的“大考”&#xff01;在这个全球化的大潮中&#xff0c;有的企业乘风破浪&#xff0c;勇攀高峰&#xff0c;也有的企业在异国他乡遭遇了“水土不服”。 面对“要么出海&#xff0c;要么出局”的抉择&#xff…

【已解决】msi格式无法下载EndNote

背景 windows11家庭中文版&#xff0c;下载EndNote&#xff0c;点击对应的msi文件&#xff0c;显示要用下列哪种方式打开&#xff0c;而不能直接下载。 解决办法 将自己的EndNote的下载文件&#xff08;.msi格式&#xff09;路径&#xff0c;全部设置为英文路径&#xff0c;…

OpenCV轮廓图的一些操作

1.按短边筛选 原始轮廓图&#xff1a; import cv2 import numpy as np# 读取轮廓图 contour_image cv2.imread(..\\IMGS\\pp_edge.png, cv2.IMREAD_GRAYSCALE)# 使用cv2.findContours()函数获取所有轮廓 contours, _ cv2.findContours(contour_image, cv2.RETR_EXTERNAL, cv2…

Firebase Local Emulator Suite详解

文章目录 Firebase Local Emulator Suite 组件安装和使用步骤1. 安装 Firebase CLI2. 初始化 Firebase 项目3. 配置模拟器4. 启动模拟器5. 配置应用程序使用本地模拟器 常见用途 Firebase Local Emulator Suite 是一组本地服务&#xff0c;可以模拟 Firebase 平台的在线服务&am…