[旧][Android] LayoutInflater 工作流程
备注
原发表于2016.06.20,资料已过时,仅作备份,谨慎参考
前言
感觉很长时间没写文章了,这个星期因为回家和处理项目问题,还是花了很多时间的。虽然知道很多东西如果只是看一下用一次,很快就会遗忘,但认认真真地做输出还是需要一定恒心的。
这次写 LayoutInflater 的工作流程,是由于小组一位成员在调用inflate 方法时,没有传入 parent 参数导致生成的布局宽高失效的问题。
这里先说原因,是因为如果 inflate 的 View,没有包含在某个 Viewgroup 下,也没有传入 parent 参数,那么他的 layout_width 等属性就会失效,这些属性是需要 View 处在某个布局下才能生效。
使用
获取 LayoutInflater
通过 LayoutInflater layoutInflater = LayoutInflater.from(context) 就可以获取到 LayoutInflater。
如果调用 View.inflate 也是先会获取 LayoutInflater,再使用 LayoutInflater 去加载布局。获取 LayoutInflater 的源码如下:
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
可以看到,我们其实也可以自己去调用 getSystemService 来获取 LayoutInflater。
加载布局
接下来,使用 layoutInflater.inflate 方法即可加载相应布局,有四个重载方法如下图:

其中 parser 参数是一个描述 View 层次的 XML 文件,在 Android 中我们就是用 XML 来描述布局的,所以直接传入布局的 int 值就可以了。
另外两个需要注意的参数是 root 和 attachToRoot,root 是指定了本次加载布局的父容器,attachToRoot 则表示是否将本次加载的内容添加到父容器中。
我们常常会碰到在 adapter 中,设置 attachToRoot 为 true 时会报错,是因为 adapter 会自己将加载的布局添加到父容器里,如果自己设置的话,就会导致重复添加了。
工作流程
所有的 inflate 到最后都会返回到下面这个方法中来进行布局加载:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
// Look for the root node.
int type;
...
final String name = parser.getName();
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (Exception e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return result;
}
}
代码较多,我去掉了有关 DEBUG 的部分,同时最后异常处理的部分也可以略过不看,那么逻辑就比较清晰了。LayoutInflater 使用 XmlPullParser 来解析布局文件,首先根据我们传入的布局参数创建根布局:
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
这个 params 参数是用来为 temp 即加载的根布局进行属性参数设置的,他有以下三种情况:
ViewGroup root 参数为 null,则返回加载的布局不做其他设置
root != null && attachToRoot == null,则使用父布局的参数对 temp 进行设置
params = root.generateLayoutParams(attrs);
temp.setLayoutParams(params);
root != null && attachToRoot != null,则将加载的布局添加到父布局,再返回父布局:
root.addView(temp, params);
接下来还会遍历加载根布局的子元素:
rInflateChildren(parser, temp, attrs, true);
这样就完成了一次布局的加载,具体是如何加载的,就得去学习 View 的工作原理了。
参考资料
这里也提示一下,你看到的资料不一定都是最正确的,尽量接受多方的信息,比如一篇博客看完后,最好是能把评论也翻看一遍。
Android LayoutInflater原理分析,带你一步步深入了解View(一)
[旧][Android] LayoutInflater 工作流程的更多相关文章
- [旧][Android] ButterKnifeProcessor 工作流程分析
备注 原发表于2016.05.21,资料已过时,仅作备份,谨慎参考 前言 在 [Android] ButterKnife 浅析 中,我们了解了 ButterKnife 的用法,比较简单. 本次文章我们 ...
- [旧][Android] View 工作原理(二)
备注 原发表于2016.05.27,资料已过时,仅作备份,谨慎参考 前言 本文大量参照<Android 开发艺术探索>及参考资料的内容整合,主要帮助自己理清 View 的工作原理.深入学习 ...
- [旧][Android] View 工作原理(一)
备注 原发表于2016.05.23,资料已过时,仅作备份,谨慎参考 前言 本文参考<Android 开发艺术探索>及网上各种资料进行撰写,目的是为自己理清 Android 中 View 的 ...
- Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...
- Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象.与Google原生AOSP有些许差异.请读者知悉. ...
- Android 4.4 Kitkat Phone工作流程浅析(七)__来电(MT)响铃流程
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...
- MapReduce简述、工作流程及新旧API对照
什么是MapReduce? 你想数出一摞牌中有多少张黑桃.直观方式是一张一张检查而且数出有多少张是黑桃. MapReduce方法则是: 1. 给在座的全部玩家中分配这摞牌. 2. 让每一个玩家数自己手 ...
- 分析Android中View的工作流程
在分析View的工作流程时,需要先分析一个很重要的类,MeasureSpec.这个类在View的测量(Measure)过程中会用到. MeasureSpec MeasureSpec是View的静态内部 ...
- Android事件分发机制三:事件分发工作流程
前言 很高兴遇见你~ 本文是事件分发系列的第三篇. 在前两篇文章中,Android事件分发机制一:事件是如何到达activity的? 分析了事件分发的真正起点:viewRootImpl,Activit ...
随机推荐
- 基于华为云服务器的FTP站点搭建
前言 主要介绍了华为云上如何使用弹性云服务器的Linux实例使用vsftpd软件搭建FTP站点.vsftpd全称是"very secure FTP daemon",是一款在Linu ...
- es6 快速入门 系列 —— 类 (class)
其他章节请看: es6 快速入门 系列 类 类(class)是 javascript 新特性的一个重要组成部分,这一特性提供了一种更简洁的语法和更好的功能,可以让你通过一个安全.一致的方式来自定义对象 ...
- IDEA构建Maven项目过慢的解决方法
创建Maven项目时在此页面添加 archetypeCatalog internal 即可
- APC 篇——备用 APC 队列
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
- 题解 - 「MLOI」小兔叽
小兔叽 \(\texttt{Link}\) 简单题意 有 \(n\) 个小木桩排成一行,第 \(i\) 个小木桩的高度为 \(h_i\),分数为 \(c_i\). 如果一只小兔叽在第 \(i\) 个小 ...
- RTSP实例解析
以下是某地IPTV的RTSP协商过程: 1.DESCRIBE 请求: //方法和媒体URL DESCRIBE rtsp://118.122.89.27:554/live/ch1008312159479 ...
- 如何在pyqt中实现亚克力磨砂效果的QLabel
前言 Windows10 在 UWP 应用中支持亚克力画刷,可以在部件的底部绘制亚克力效果的背景图.下面我们使用 QLabel 来模拟这个磨砂过程. 实现方法 MSDN 文档中介绍了亚克力材料的配方, ...
- Luogu P1438无聊的数列
洛谷 P1438无聊的数列 题目链接 点这里! 题目描述 维护一个数列\(a_i\),支持两种操作: 给出一个长度等于 \(r-l+1\)的等差数列,首项为\(k\) 公差为\(d\) 并将它对应加到 ...
- ApacheCN JavaScript 译文集 20211122 更新
JavaScript 编程精解 中文第三版 零.前言 一.值,类型和运算符 二.程序结构 三.函数 四.数据结构:对象和数组 五.高阶函数 六.对象的秘密 七.项目:机器人 八.Bug 和错误 九.正 ...
- ApacheCN PHP 译文集 20211101 更新
PHP 入门指南 零.序言 一.PHP 入门 二.数组和循环 三.函数和类 四.数据操作 五.构建 PHP Web 应用 六.搭建 PHP 框架 七.认证与用户管理 八.建立联系人管理系统 使用 PH ...