Android View之布局加载流程
1.引言
最近准备重新学习下Android,加深理解,快速形成自己的知识结构体系。最先学习的就算View部分,从自定义View到Activty层次结构,到layout加载过程。等等都会看一遍,在此记录下Layout的加载过程
2.正题
2.1 Activity的流程加载
Activity类中setContentView 追踪(善于用bookMark)
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
追踪代码,PhoneWindow的setContentView方法:

mLayoutInflater.inflate(layoutResId,mContentParent)
由代码片段可以看出来:layoutResId的父布局就是mContentParent。那么mContentParent究竟是什么呢?
我们知道DecorView 包括TitleView +ContentView.

追踪代码:installDescor():

generateLayout()方法:
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
// 获得窗体的 style 样式
TypedArray a = getWindowStyle();
// 省略大量无关代码
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
//填充带有 style 和 feature 属性的 layoutResource (是一个layout id)
View in = mLayoutInflater.inflate(layoutResource, null);
// 插入的顶层布局 DecorView 中
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
// 找到我们XML文件的父布局 contentParent
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
// 省略无关代码
mDecor.finishChanging();
// 返回 contentParent 并赋值给成员变量 mContentParent
return contentParent;
}
给DecorView添加一个名字为mContentRoot的view。并且mContentRoot里面包含了一个id为ID_ANDROID_CONTENT的 mContentParent.
得到了mContentParent之后,在根据mLayoutInflater.inflate(layoutResId,mContentParent) 就将Layout布局加载进了DecorView,然后这个视图才能被我们看到。
验证:

说明了mContentParent是FramLayout
3.AppCompatActivity 加载View得过程
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
getDelegate():
@NonNull
public AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, this);
}
return mDelegate;
}
跟踪create()方法,
public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
return create(activity, activity.getWindow(), callback);
}
activity.getWindow() 由上面可知,得到的肯定是PhoneWindow。问题来了,activity这个时候真的能得到一个非null的PhoneWindow吗?。发现在activity调用attach方法的时候就会初始化PhoneWindow:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
......
}
Activity.attach是在performLaunchActivity中本调用,也就是在ActivityThread中被调用。所以在Activity中任何时候getWindow(),都能得到PhoneWindow。
继续跟踪代码:
create方法调用的是:
private static AppCompatDelegate create(Context context, Window window,
AppCompatCallback callback) {
if (Build.VERSION.SDK_INT >= 24) {
return new AppCompatDelegateImplN(context, window, callback);
} else if (Build.VERSION.SDK_INT >= 23) {
return new AppCompatDelegateImplV23(context, window, callback);
} else if (Build.VERSION.SDK_INT >= 14) {
return new AppCompatDelegateImplV14(context, window, callback);
} else if (Build.VERSION.SDK_INT >= 11) {
return new AppCompatDelegateImplV11(context, window, callback);
} else {
return new AppCompatDelegateImplV9(context, window, callback);
}
}
setContentView 是在AppCompatDelegateImplV9类中被重写,也就是说最终是调用AppCompatDelegateImplV9.setContentView();
@Override
public void setContentView(int resId) {
ensureSubDecor();
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);
mOriginalWindowCallback.onContentChanged();
}
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
很容易让我们想到mSubDecor 是不是等同于上文中的mContentRoot 呢?
看看ensureSubDecor怎么写的:
if (mOverlayActionMode) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_screen_simple_overlay_action_mode, null);
} else {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
}
subDecor 是系统提供的ViewGroup 里面有一个android.R.id.content布局,和mContentRoot 作用一模一样。
基本上分析到此结束,也是比较简单。
Android View之布局加载流程的更多相关文章
- android源码解析(十七)-->Activity布局加载流程
版权声明:本文为博主原创文章,未经博主允许不得转载. 好吧,终于要开始讲讲Activity的布局加载流程了,大家都知道在Android体系中Activity扮演了一个界面展示的角色,这也是它与andr ...
- Android View的加载流程
什么是Activity? Activity是 用户操作的可视化界面:它为用户提供了一个放置视图和交互操作的窗口.采用setContentView的方法提供.因此,可以理解Activity.Window ...
- Android 8.1 SystemUI虚拟导航键加载流程解析
需求 基于MTK 8.1平台定制导航栏部分,在左边增加音量减,右边增加音量加 思路 需求开始做之前,一定要研读SystemUI Navigation模块的代码流程!!!不要直接去网上copy别人改的需 ...
- 8. Android加载流程(打包与启动)
移动安全的学习离不开对Android加载流程的分析,包括Android虚拟机,Android打包,启动流程等... 这篇文章 就对Android的一些基本加载进行学习. Android虚拟机 And ...
- Android必学-异步加载+Android自定义View源码【申明:来源于网络】
Android必学-异步加载+Android自定义View源码[申明:来源于网络] 异步加载地址:http://download.csdn.net/detail/u013792369/8867609 ...
- Android 自定义View修炼-自定义加载进度动画XCLoadingImageView
一.概述 本自定义View,是加载进度动画的自定义View,继承于ImageView来实现,主要实现蒙层加载进度的加载进度效果. 支持水平左右加载和垂直上下加载四个方向,同时也支持自定义蒙层进度颜色. ...
- Android 如果布局中有ScrollView和Fragment或者带有滚动条的布局进行嵌套,布局加载完成页面无法定位到顶部的情况
页面无法定位到顶部: 1.ScrollView中嵌套Fragment(Fragment中可能有想ScrollView,ListView带有滚动条的控件). 2.ScrollView嵌套ScrollVi ...
- FrameWork内核解析之布局加载与资源系统(三)
阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680本篇文章将继续从以下两个内容来介绍布局加载与资源系统: [ LayoutM ...
- java攻城狮之路(Android篇)--widget_webview_metadata_popupwindow_tabhost_分页加载数据_菜单
一.widget:桌面小控件1 写一个类extends AppWidgetProvider 2 在清单文件件中注册: <receiver android:name=".ExampleA ...
随机推荐
- 微信小程序 - 自定义tabbar(组件)
配置项(关于使用组件) index.wxml <!-- tabBar:tabBar配置 activeIndex: 激活页面下标 slots: 多插槽配置(需与页面一致) --> <t ...
- Aerospike系列:3:aerospike特点分析
1. 数据存放 数据可以放内存,也可以放SSD. 数据放内存时速度肯定会很快,但这和memcache一样,相比memcache性能并没有优势 数据放内存时可以进行持久化配置,但文档只有一个地方提了 ...
- Openwrt15.05网关后pptp外拨失败的解决办法
路由器升级openwrt chaos_calmer 15.05版后发现NAT后面的客户端外拨pptp vpn服务器失败,经google后得知,在14.07版本中默认安装的又一个叫做 kmod-ipt- ...
- Oracle内存结构:SGA PGA UGA
内存结构是oracle数据库最重要的组成部分之一,在数据库中的操作或多或少都会依赖到内存,是影响数据库性能的重要因素Oracle数据库中包括3个基本的内存结构: 一. 系统全局区 (System G ...
- eclipse svn新增文件不显示在文件列表,只有修改文件可以提交!
1.情景展示 eclipse修改的文件可以正常提交,但是新增的文件没有显示在提交列表中,导致无法提交! 2.解决方案 选中要提交的文件-->右键-->Team-->提交 勾选上这 ...
- 读取csv文件并打印其结果
In [5]: import pandas as pd In [6]: df=pd.read_csv('https://raw.githubusercontent.com/alstat/Analysi ...
- 一网打尽2013最常用的NoSQL数据库
摘要:与关系数据库相比,每个NoSQL都有自己不同的适用场景,这里带大家盘点文档数据库.图数据库.键值数据存储.列存储数据库与内存数据网络等领域的常用的NoSQL. 在几年内,NoSQL数据库一直 ...
- JavaScript的NaN-唯一 一个自己不等于自己的对象!!
JavaScript的NaN为什么不等于NaN 在JS中 Object === Object 感觉没有任何问题 这两个都代表的一个东西 但是如果你试过 NaN === NaN 是返回false为什么呢 ...
- 转:ogre的编译及安装
ogre在Windows环境下的编译及安装过程: 1.从下面网址下载OGRE 1.8.1 Source For Windows.Dependencies source repository with ...
- 【RS】Local Latent Space Models for Top- N Recommendation-利用局部隐含空间模型进行Top-N推荐
[论文标题]Local Latent Space Models for Top- N Recommendation (KDD-2018 ) [论文作者]—Evangelia Christakopou ...