当前位置: 首页 > 编程日记 > 正文

component是什么接口_【Android每日一题】从Activity创建到View呈现中间发生了什么?...

640683e4aa22b34c1e46337fd3bc0fe1.png

前言

前段时间公司招人,作为面试官,我经常让面试者简述View的绘制流程。他们基本都能讲明白View的测量(measure)、布局(layout)、绘制(draw)等过程。

还有少数人会提到DecorView和ViewRootImp的作用。但是,当我继续追问关于Window的内容时,几乎没有人回答上来。而本章将会带你深入理解Window、DecorView、ViewRootImp。

除此之外,你还能在本章找到以下问题的答案:
  1. 为什么要有设计Window?
  2. 子线程真的不能更新UI吗?
  3. 为什么在Activity的onCreate方法中无法获取View的宽和高?

图解Activity启动到View显现过程

f678c0c943e49ae8439a276ef6ec08c1.png
上图出现了五个对象:Activity、Window、WindowManager、DecorView、ViewRootImpl,我分别解释一下它们的作用。
  • Activity:Activity像是一个指挥官,它不处理具体的事务,只在适当的时候指挥Window/WindowManager工作。例如:在attach时创建Window对象、onResume后通知WindowManager添加view。
  • Window:Window是一个窗口,它是View的容器。Android中的视图以View树的形式组织在一起,而View树必须依附在Window上才能工作。一个Window对应着一个View树。启动Activity时会创建一个Window,显示Dialog时也会创建一Window。因此Activity内部可以有多个Window。由于View的测量、布局、绘制只是在View树内进行的,因此一个Window内View的改动不会影响到另一个Window。Window是一个抽象类,它只有一个实现类PhoneWindow。
  • WindowManager:WindowManager是Window的管理类。它不直接操作Window,而是操作Window内的DecorView。WindowManager是一个接口。它的具体实现类是WindowManagerImpl。
public 
  • DecorView是View树的顶级View,它是FrameLayout的子类。根据Activity设置的Theme,DecorView会有不同布局。但无论布局怎么变,DecorView都有一个Id为R.id.content的FrameLayout。Activity.setContentView()方法就是在这个FrameLayout中添加子View。
  • ViewRootImpl是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRootImpl来完成的。

源码解密

在Android插件化之启动Activity中,我介绍过Activity的启动流程。其中handleLaunchActivity()方法是启动Activity的核心方法。本节就以它为切入点开始分析。

private 

handleLaunchActivity()主要调用了两个方法:performLaunchActivity()和handleResumeActivity()

  • performLaunchActivity:完成Activity的创建,以及调用Activity的 onCreate()和onStart()方法。
  • handleResumeActivity:调用Activity的onResume()方法,处理View的呈现。

performLaunchActivity

我们进入performLaunchActivity()方法,核心代码如下:

private 

performLaunchActivity()主要做了以下几件事:

  1. 创建Activity。
  2. 创建Context。
  3. 调用Activity.attach(),创建Window,关联WindowManager。
  4. 调用Activity.onCreate()。
  5. 调用Activity.onStart()。

attach

上面说了,在Activity.attach()方法执行时会创建Window并为Window关联WindowManager。我们看一下伪代码。

final 

setContentView

顺着流程图,Activity.setContentView()方法会被调用。Activity.setContentView()内又直接调用了PhoneWindow.setContentView()。我们直接看PhoneWindow.setContentView()的源码。

private 

如果mContentParent为null,会执行installDecor()方法。generateDecor()源代码很长,但是它的逻辑很简单主要是根据Activity Theme的不同,初始化不同的布局。

DecorView的布局虽然不同,但它们都一个Id为R.id.content的FrameLayout。

Activity.setContentView()就是在这个FrameLayout中添加子View。

handleResumeActivity

performLaunchActivity()执行完后,紧接着执行handleResumeActivity()。

final 

handleResumeActivity()处理的事情比较多。我总结为以下几个过程:

  • 通过performResumeActivity()处理Activity的onRestart onResume的生命周期。
  • 将DecorView设置为InVisible。
  • 通过WindowManager.addView()将DecorView绘制完成。
  • 将DecorView设置为Visiable。
  • 通知AMS Activity启动完成。

WindowManger.addView()

前面说过,WindowManger是一个抽象类,它的实现类是WindowManagerImpl。WindowManager.addView()封装了View绘制的细节。我们着重看一下。

public 

WindowManagerImpl.addView会调用WindowManagerGlobal.addView()。在WindowManagerGlobal.addView()方法执行之前,会先执行applyDefaultToken()方法。

这个方法其实是给传进来的DecorView加一个身份标识,表示这个DecorView属于哪个Activity。这样系统(WindowManagerService)才会知道要把DecorView绘制到哪个Activity。

我们继续追踪WindowManagerGlobal.addView(),伪代码如下:

private 

首先会创建ViewRootImpl,随后把View、ViewRootImpl、LayoutParams都保存在List中,以供将来更新UI使用。

它们的index值相同,这样就三者就对应起来了。最后,调用ViewRootImpl.setView()方法。

ViewRootImpl.setView()

public 

ViewRootImpl.setView()的伪代码有两句,但我们只关心requestLayout。因为mWindowSession.addToDisplay()就是通过IPC通知WMS去渲染,我们再去分析WMS意义已经不大了。requestLayout()方法首先会检查当前执行的线程是不是UI线程,随后调用scheduleTraversals()。

scheduleTraversals会把本次请求封装成一个TraversalRunnable对象,这个对象最后会交给Handler去处理。最后ViewRootImpl.performTraversals()被调用。调用链如下:

final 

performTraversals()主要是处理View树的measure、layout、draw等流程。不清楚的同学可以去看《Android开发艺术探索》第四章,我在这里就不继续深入了。

总结

下面我回答文章前言部分提出的几个问题。

为什么要有设计Window?
要理解Window需要从面向对象的角度出发。
  1. 假如没有Window,那Window管理View树的代码必然会放到Activity中。这样Activity就变得十分庞大,这与我们前面说的Activity指挥官的角色相违背。
  2. 把View树的管理工作封装到Window后,在调用Dialog.show()、Dialog.hide()等Window切换时,Activity只需要负责Window的显示和隐藏即可。
  3. View的测量、布局、绘制只是在View树内进行的,把一个View树封装在一个Window中方便视图管理。
子线程真的不能更新UI吗?
更新视图时,线程检查是在ViewRootImpl的checkThread()中。ViewRootImpl的初始化是在Activity的onResume()方法之后。因此,如果有子线程在onResume之前更新UI是可以成功的。当然还有一种Hook ViewRootImpl的mThread的方法也可以更新UI。这里不做介绍了。Activity的onCreate方法为什么无法获取View的宽和高
这个问题和子线程不能更新UI的问题很像,也是方法执行时机的一个问题。View的measure、layout、draw。发生在Activity.onResume()之后,因此在onResume()之前都是无法获取View的宽、高等信息的。

作者:青霉素

4a853af2a0dfec3abe1e6ebc0992ecc0.png

看完点赞,养成习惯,微信搜一搜「 程序猿养成中心 」关注这个喜欢写干货的程序员。

另外更有Android一线大厂面试完整考点、资料更新在我的【Github】,有面试需要的朋友们可以去参考参考,如果对你有帮助,可以点个Star哦!

Github地址https://github.com/733gh/xiongfan

相关文章:

wp 删除独立存储空间文件(多级非空文件夹删除)

void DelFile(string unZipFilePath)//unZipFilePath第一次传递的是根目录名 { using (var store IsolatedStorageFile.GetUserStoreForApplication()) { if (store.DirectoryExists(unZipFilePath)) { …

重拾博客小序与杂思

寒假期间,条件所限,不能上网,也不能更新博客。寒假结束,懈怠了两个星期,打算重拾博客,继续更新。这学期(2012年2月到2012年8月)在专业学习上将突出几个集中研究的领域,在…

Ubuntu iso镜像文件写入U盘

Ubuntu iso镜像文件写入U盘 Ubuntu iso镜像文件写入U盘方法 分步指南 命令行输入 usb-creator-gtk如下:3、Device 选择插入的U盘 4、image 选择镜像文件 5、make startup disk

页面布局让footer居页面底部_网站各页面该如何布局关键词优化提升排名?

在网站优化中,最值得关注的一个事情就是关键词的布局,因为关键词的布局直接影响着网站的排名。那么怎样布局关键词才能提高页面和关键词的相关性,并提高网站排名呢?下面一起来看看。一、利用HTML标签布局关键词众所周知&#xff0…

Linux中如何配置IP

与网络相关的文件:1) /etc/sysconfig/network 设置主机名称及能否启动Network2) /etc/sysconfig/network-scripts/ifcfg-eth0设置网卡参数的文件3) /etc/modprobe.conf 开机时用来设置加载内核模块的文件4) /etc/resolv.conf 设置DNS IP(解析服务器&…

《DSP using MATLAB》Problem 5.7

代码&#xff1a; %% %% Output Info about this m-file fprintf(\n***********************************************************\n); fprintf( <DSP using MATLAB> Problem 5.7 \n\n);banner(); %% % -------------------------------------------…

一般将来时语法课教案_「英语语法」一般过去时用法技巧全解

大家好&#xff0c;我是教课蚪英语的张老师&#xff0c;今天我们来学习英语语法100讲的第一课&#xff0c;一般过去时&#xff01;一、首先我们了解一下什么是一般过去时&#xff1f;英语语法1. 概念&#xff1a;描述过去的状态或过去的动作。 在英语中&#xff0c;非现在的以前…

修改Ubuntu的启动logo

修改Ubuntu的启动logo 原文链接: https://my.oschina.net/jmjoy/blog/380262 内容: Plymouth splash screen is the initial splash screen at boot-up.Ubuntu 10.04 uses Plymouth instead of xsplash to manage the fancy boot graphics.If you want something different,y…

每周四十小时,你有多少是在为自己干活?

努力工作为什么&#xff1f;普通人不外乎希望加薪、升职&#xff0c;过的更好。 但是&#xff0c;要想达到这个目标&#xff0c;靠什么&#xff1f; 普通人当然要靠提升自己的能力和经验。 可是&#xff0c;你是不是已经发现&#xff0c;工作最踏实的&#xff0c;却未必取得最好…

在Linux下查看共享文件夹

一般情况&#xff0c;我们用到smbclient&#xff0c;常用方法所如下&#xff1a;#smbclient -L //IP地址或计算机名smbclient是samba的Linux客户端&#xff0c;在Linux机器上用来查看服务器上的共享资源&#xff0c;也可以向ftp一样&#xff0c;用户可以等里samba服务器&#x…

算法复杂度的定义

算法复杂度分为时间复杂度和空间复杂度。其作用&#xff1a; 时间复杂度是指执行算法所需要的计算工作量&#xff1b;而空间复杂度是指执行这个算法所需要的内存空间。&#xff08;算法的复杂性体现在运行该算法时的计算机所需资源的多少上&#xff0c;计算机资源最重要的是时间…

C#操作OFFICE一(EXCEL)

C#操作Excel! publicclassImportExportToExcel { private string strConn ; private System.Windows.Forms.OpenFileDialog openFileDlgnew System.Windows.Forms.OpenFileDialog(); private System.Windows.Forms.SaveFileDialog saveFileDlg…

c语言最小费用流_策略算法工程师之路-图优化算法(一)(二分图amp;最小费用最大流)...

目录1.图的基本定义2.双边匹配问题2.1 二分图基本概念2.2 二分图最大匹配求解2.3 二分图最优匹配求解2.4 二分图最优匹配建模实例2.4.1 二分图最优匹配在师生匹配中的应用2.4.2 二分图最优匹配在多对多拼车算法中的应用3.网络最大流3.1 网络流基本定义3.2 最大流的问题线性规划…

linux 查看库的安装信息

ldconfig -p | grep 库名(例如&#xff1a;lib***&#xff09; 比如&#xff1a; ldconfig -p | grep libcrypto

Asp.net无刷新调用后台实体类数据并以Json格式返回

新建一般处理程序public class Temp {public int Index { get; set; }public string Description { get; set; }public string ImagePath { get; set; }public DateTime MyDate { get; set; } }//数据源 List<Temp> listTemp new List<Temp>(){new Temp(){ Index1…

HDU 排名(简单题)

好久没在oj上做题了&#xff0c;刚开始第二天做一道简单题的心得记录。 1 #include <cstdio>2 #include <cstring>3 #include <string>4 #include <iostream>5 #include <algorithm>6 using namespace std;7 8 /*9 超级无语的错误&#xff0c;#d…

linux系统操作常见问题(ubuntu和opensuse)

在玩linux的过程中&#xff0c;会遇到各种看似奇怪的问题&#xff0c;这些问题往往让那些刚刚接触linux没多久的人不知所措&#xff0c;心中烦躁&#xff0c;这里把我曾经遇到对各种问题列出来&#xff0c;供喜欢linux对人参考&#xff1a; linux下以root身份成功运行chromium…

java iso8583 socket 服务_JAVA客户端amp;服务器的socket通信

JAVA客户端&服务器的socket通信socket是两台主机之间的一个连接通道&#xff0c;它可以完成七个基本操作&#xff1a;发送远程机器发送数据接收数据关闭连接绑定端口监听入站数据再绑定端口上接收来自远程机器的连接在客户端上使用socket程序用构造函数创建一个新的sockets…

linux 扩容

如何在linux系统中增加一块硬盘&#xff0c;并且格式化它呢&#xff1a; 我是使用VMware-workstation-full-7.1.0-261024.exe来做实验的。&#xff08;1&#xff09;使用VMware-workstation 给虚拟机增加一块硬盘&#xff0c;如下图所示&#xff1a;&#xff08;2&#xff09;然…

Python3 xml模块的增删改查

xml数据示例 ?1234567891011121314151617181920212223242526<data><country name"Liechtenstein"><rank updated"yes">2</rank><year updated_by"Alex">2009</year><gdppc>141100</gdppc><…

mysql 函数返回表格_mysql 数据分析如何实现日报、周报、月报和年报?

推荐阅读&#xff1a;MySQL复习&#xff1a;20道常见面试题(含答案)21条MySQL性能调优经验秋招Java面试大纲&#xff1a;Java并发spring数据库RedisJVMNetty等以天为统计周期&#xff0c;是常见需求。周报、月报更是常见需求。长周期项目&#xff0c;甚至有年报需求。我已经掌握…

如何开启to 日志

命名 gc_date %Y-%m-%d %H:%M:%S.log&#xff0c;11月15号21:51:58开始生成gc日志 注&#xff1a;在哪个目录启动tomcat&#xff0c;就会在哪个目录生成gc日志文件 转载于:https://www.cnblogs.com/qqzy168/archive/2012/11/16/2772636.html

联想电脑 Realtek RTL8821CE 无线网卡 驱动安装 16.04/18.04

原文连接: https://askubuntu.com/questions/1071299/how-to-install-wi-fi-driver-for-realtek-rtl8821ce-on-ubuntu-18-04 内容&#xff1a; As far as I can tell, at the time of writing this, there is not yet a Wifi Driver for the Realtek RTL8821CE in the officia…

PXE网络无人职守安装

PXE网络无人职守安装DHCP、TFTP、NFS、APACHE为同一台服务器&#xff1a;192.168.0.1yum -y install dhcp xinetd tftp-server syslinux nfs-utils httpd system-config-kickstart一、配置DHCP1.默认的DHCP配置文件内容是空的&#xff0c;可以拷贝usr目录下的样板文件修改cp /u…

贪心算法之硬币问题

有1元&#xff0c;5元&#xff0c;10元&#xff0c;50元&#xff0c;100元&#xff0c;500元的硬币个C1&#xff0c;C2&#xff0c;C3&#xff0c;C4&#xff0c;C5&#xff0c;C6枚&#xff0c;用这些硬币来支付A元&#xff0c;最少需要多少枚硬币&#xff1f; #include<io…

button按钮样式_一篇文章带你了解CSS3按钮知识

在实际开发中&#xff0c;按钮的应用是必不可少。使用 CSS 来制作按钮&#xff0c;可以更有新意&#xff0c;更有趣&#xff0c;也可以自定义自己想要的样式。 一、平面样式CSS按钮 平面样式按钮的使用现在非常流行&#xff0c;并且符合无处不在的平面设计趋势。&#xff0c;这…

Ubuntu 18.04时间同步

Ubuntu 18.04时间同步原文连接: 原文链接 内容&#xff1a; Sync Clock with Time Servers through the Command Line Check Current Time Status The timedatectl command lets you check the current time status of your system clock. Open your Ubuntu terminal through…

UVa 10051 Tower of Cubes(类似LIS)

题意&#xff1a; 一些重量递增而且各个面都有颜色的立方体&#xff0c;要将这些立方体堆成一个塔&#xff0c;要求两个接触面同色&#xff0c;而且下面的立方体更重。求塔的最大高度。 思路&#xff1a; 用求LIS的思想&#xff0c;无非是多了几个状态。dp[i][j]表示前i个箱子&…

【十五分钟Talkshow】fmplan(十五分钟计划)的初步想法

摘要信息 这个演讲将概述提出了我最近开始的一个名为“fmplan”的 基于互联网的教育计划 }计划简介}内容简介}目标受众}学习环境}支持和帮助讲义地址 http://www.xizhang.com/fmplan/resources/fmplan_overview.pdf 视频地址 http://www.tudou.com/programs/view/hhS5U-o-qRc/…

ACC026简要题解

这场AGC是时间正好在NOI之前休养生息的日子里&#xff0c;果断选择了放弃(虽然也从没有用大号打过)。在随便做完了前几题之后就踏上了去长沙的旅程。NOI系列比赛总是休闲无比&#xff0c;咕咕不断&#xff0c;竟然连开幕式都能咕&#xff0c;今天AK了一下笔试之后就来刚后两题&…