[旧][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 ...
随机推荐
- 【刷题-LeetCode】162 Find Peak Element
Find Peak Element A peak element is an element that is greater than its neighbors. Given an input ar ...
- Linux下安装confluence汉化破解版
Atlassian Confluence(简称Confluence)是一个专业的wiki程序.它是一个知识管理的工具,通过它可以实现团队成员之间的协作和知识共享.Confluence 不是一个开源软件 ...
- Error:(3, 21) java: 程序包javax.servlet不存在的解决方法
采用 https://blog.csdn.net/GK666_/article/details/106442929得到解决
- Kubernetes的Pod进阶(十一)
一.Lifecycle 官网:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/ 通过前面的分享,关于pod是什么相信看 ...
- WinDbg 分析dump
1.生成dump文件. 在代码捕获异常,并将异常写入dump文件. #include "stdafx.h" #include <Windows.h> #include ...
- 使用 Frp 和 Docker 通过远程桌面和 SSH 来远程控制 Windows(反向代理)
最新博客文章链接 大体思路 使用 Docker 容器,在云服务器上部署 Frps 容器来中转流量,在被控制的 Windows 上部署 Frpc 容器来暴露内网的服务,在主控制端的 Windows 上直 ...
- [USACO18DEC]Sort It Out P
初看本题毫无思路,只能从特殊的 \(K = 1\) 出发. 但是直接考虑构造一组字典序最小的方案还是不好构造,可以考虑先手玩一下样例.通过自己手玩的样例可以发现,貌似没有被选出来的数在原排列中都是递增 ...
- 总结一下Mac快捷键的图形符号
Mac中主要有四个修饰键,分别是Command,Control,Option和Shift.这四个键分别有自己的图案,他们经常出现在Mac应用程序中的菜单栏里,方便你随时学习新的快捷键.
- 前端常见原生方法的实现(bind,promise,new,extends,深拷贝,函数防抖,函数节流)
前端原生方法的实现,这里写一下常见的一些实现: 1.bind Function.prototype.bind2 = function (context) { var self = this; retu ...
- Javascript 生成全局唯一标识符 (GUID,UUID)
全局唯一标识符(GUID,Globally Unique Identifier)也称作 UUID(Universally Unique IDentifier) . GUID是一种由算法生成的二进制长度 ...