当我们在Activity中调用setContentView,它到底做了什么呢

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}

我们跳转到AppCompatActivity的setContentView方法

@Override
public void setContentView(@LayoutRes int layoutResID) {
//返回了AppCompatDelegate对象
getDelegate().setContentView(layoutResID);
}

然后又调用了getDelegate().setContentView()

@NonNull
public AppCompatDelegate getDelegate() {
if (mDelegate == null) {
//跳转到create()方法可以看到,该方法返回的是一个AppCompatDelegateImpl对象
mDelegate = AppCompatDelegate.create(this, this);
}
return mDelegate;
}

我们直接去AppCompatDelegateImpl中查看setContentView方法,可以看到,Activity中的

setContentView最后调用了AppCompatDelegateImpl的setContentView方法

@Override
public void setContentView(View v) {
ensureSubDecor();
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);
mOriginalWindowCallback.onContentChanged();
}

ensureSubDecor又调用了createSubDecor方法

private ViewGroup createSubDecor() {
....
//步骤1
//mWindow是PhoneWindow,该对象是在Activity.java attach()方法中初始化
//该方法会触发DecorView的创建
mWindow.getDecorView();
...
//根据不同的情形加载不同的布局文件来初始化subDecor,具体过程可以不细究
...
//步骤2
//可以先看完之后的步骤可以再来看这里
//调用PhoneWindow.setContentView()方法,将创建好的subDecor添加到mContentParent,
//mContentParent是在installDecor方法中调用generateLayout()创建出来的
//在之后的Android版本中,我们的布局其实是添加到了subDecor中,而subDecor又会添加到
//PhoneWindow.mContentParent,mContentParent其实是DecorView的一个子View,初始化过程见installDecor方法
mWindow.setContentView(subDecor);
}

mWindow.getDecorView会调用PhoneWindow的getDercorView(),里面会调用installDecor()

private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
//该方法会直接new DecorView()
mDecor = generateDecor(-1);
...
...
}
if (mContentParent == null) {
//生成一个FrameLayout,用于添加AppCompatDelegateImpl.createSubDecor()
//中创建的subDecor,该view是在setContentView中添加的,见步骤2
mContentParent = generateLayout(mDecor);
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent); if (decorContentParent != null) {
mDecorContentParent = decorContentParent;
...
...
}

generateDecor()方法会创建一个DecorView,继承自FrameLayout,是PhoneWindow的内部类,

新版本的Android源码已独立出来

protected DecorView generateDecor(int featureId) {
...
...
return new DecorView(context, featureId, this, getAttributes());
}

generateLayout方法根据不同的主题样式来加载不同系统的布局,

最终返回一个FrameLayout对象,可以通过findViewById(android.R.id.content)获取

protected ViewGroup generateLayout(DecorView decor){
...
...
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
...
return contentParanet;
}

回到步骤2

最后我们回到AppCompatDelegateImpl.setContentView中去

@Override
public void setContentView(int resId) {
ensureSubDecor(); //这个对象就是PhoneWindow下面的generateLayout()创建出来的FrameLayout
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews(); //最后将我们传进来的布局文件实例化,然后添加进去
LayoutInflater.from(mContext).inflate(resId, contentParent); //最后会回调onContentChanged()生命周期方法
mOriginalWindowCallback.onContentChanged();
}

setContentView流程

总结:

setContentView()会触发DecorView的创建,最后会将我们的布局文件添加到DecorView,完成布局文件的加载,

这也就是为什么我们在onCreate()方法中获取不到view的宽高,因为该过程只加载了布局,并没有对布局View进行大小的测量.

setContentView源码分析的更多相关文章

  1. Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  2. android高级---->AsyncTask的源码分析

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask,它在子线程更新UI的例子可以参见我的博客(android基础---->子线程更新UI).今天我们通过一个小的案例 ...

  3. Android Handler处理机制 ( 一 )(图+源码分析)——Handler,Message,Looper,MessageQueue

    android的消息处理机制(图+源码分析)——Looper,Handler,Message 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习 google大牛们的设计思想. ...

  4. 源码分析——从AIDL的使用开始理解Binder进程间通信的流程

    源码分析——从AIDL的使用开始理解Binder进程间通信的流程 Binder通信是Android系统架构的基础.本文尝试从AIDL的使用开始理解系统的Binder通信. 0x00 一个AIDL的例子 ...

  5. Android事件传递机制详解及最新源码分析——View篇

    摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处. 对于安卓事件传递机制相信绝大部分开发者都听说过或者了解过,也是面试中最常问的问题之一.但是真正能从源码角度理解具体事件传递流程的相信并不多, ...

  6. Android事件传递机制详解及最新源码分析——ViewGroup篇

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 在上一篇<Android事件传递机制详解及最新源码分析--View篇>中,详细讲解了View事件的传递机制,没掌握或者掌握不扎实的小伙伴 ...

  7. Android事件传递机制详解及最新源码分析——Activity篇

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 在前两篇我们共同探讨了事件传递机制<View篇>与<ViewGroup篇>,我们知道View触摸事件是ViewGroup传递 ...

  8. Android HandlerThread 源码分析

    HandlerThread 简介: 我们知道Thread线程是一次性消费品,当Thread线程执行完一个耗时的任务之后,线程就会被自动销毁了.如果此时我又有一 个耗时任务需要执行,我们不得不重新创建线 ...

  9. onCreate源码分析

    原文地址Android面试题-onCreate源码都没看过,怎好意思说自己做android Activity扮演了一个界面展示的角色,堪称四大组件之首,onCreate是Activity的执行入口,都 ...

随机推荐

  1. 【主流技术】ElasticSearch 在 Spring 项目中的实践

    前言 ElasticSearch简称es,是一个开源的高扩展的分布式全文检索引擎. 它可以近乎实时的存储.检索数据,其扩展性很好,ElasticSearch是企业级应用中较为常见的技术. 下面和大家分 ...

  2. MVVM,MVC,MVP的区别

    MVC.MVP 和 MVVM 是三种常见的软件架构设计模式,主要通过分离关注点的方式来组织代码结构,优化开发效率. 在开发单页面应用时,往往一个路由页面对应了一个脚本文件,所有的页面逻辑都在一个脚本文 ...

  3. 好用到爆!GitHub 星标 32.5k+的命令行软件管理神器,功能真心强大!

    前言(废话) 本来打算在公司偷偷摸摸给星球的用户写一篇编程喵整合 MongoDB 的文章,结果在通过 brew 安装 MongoDB 的时候竟然报错了.原因很简单,公司这台 Mac 上的 homebr ...

  4. [LINUX] 像电影里的黑客一样用 terminal 作为日常开发

    目录 1.效果预览 2.具体实现 2.1 定位鼠标位置 2.2 获取屏幕位置 2.3 计算鼠标在哪个窗口 2.4 1920x1080 平铺效果设计 2.5 1280x1024 平铺效果设计 3 代码 ...

  5. linux查询文件或者文件夹

    查找目录:find /(查找范围) -name '查找关键字' -type d // 查找fastdfs_storage_data文件夹 find / -name fastdfs_storage_da ...

  6. HDFS数据平衡

    一.datanode之间的数据平衡 1.1.介绍 ​ Hadoop 分布式文件系统(Hadoop Distributed FilSystem),简称 HDFS,被设计成适合运行在通用硬件上的分布式文件 ...

  7. 8.4 苹果macOS电脑如何安装Java开发环境(JDK)

    和Windows电脑安装差不多. 下载 来到JDK官方下载界面,点击Java SE 8(简称JDK 8)后面的JDK下载,来到该界面,先同意协议,然后下载对应平台的JDK,我们这里下载Mac OS X ...

  8. NC20861 兔子的逆序对

    NC20861 兔子的逆序对 题目 题目描述 兔子最近喜欢上了逆序对.一个逆序对 \((i,j)\) 需要满足 \(i < j\) 且 \(a_i > a_j\) .兔子觉得只是求一个序列 ...

  9. 基于 Github Actions 自动部署 Hexo 博客

    前言 前不久使用了 Hexo 搭建独立博客,我是部署在我的腾讯云轻量应用服务器上的,每次都需要 hexo deploy 然后打包.上传.解压和刷新 CDN,非常麻烦.我的服务器配置也不高 2C2G 无 ...

  10. zenmap安装

    发现最新版的KALI不带zenmap了,下面是安装步骤: 安装包转换工具:sudo apt-get install alien fakeroot -y 下载并转换:https://nmap.org/d ...