Android LayoutInflater和findViewById 源码详解
LayoutInflater大家很熟悉,简单点说就是布局文件XML解析器,setContentView函数也是调用了LayoutInflater
用法:
View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
LayoutInflater lyInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
上面的用法本质上都是一样.
控制台打印 重复调用LayoutInflater.from(this) 同一个进程下面 实例是单例
com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80
com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80
com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80
首先 LayoutInflater 是一个抽象类,实例化对象是从Service取出的。但是并没有到底层Binder去实例化对象。最终实例对象是PhoneLayoutInflater类
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;
}
从Activity父类可以找到 getSystemService方法
public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(mBase).cloneInContext(this); //在这个地方实例化的,主要关联到mBase Context对象实例
}
return mInflater;
}
return mBase.getSystemService(name);
}
重点是Context的实例化对象 有个子类 ContextImpl.java 里面注册了相关Service
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
SYSTEM_SERVICE_MAP 是个hashMap 注册的服务都存在这个地方,对象被缓存。
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>(); abstract static class StaticServiceFetcher extends ServiceFetcher {
private Object mCachedInstance; @Override
public final Object getService(ContextImpl unused) {
synchronized (StaticServiceFetcher.this) {
Object service = mCachedInstance;
if (service != null) {
return service;
}
return mCachedInstance = createStaticService();
}
}
public abstract Object createStaticService(); //这个用于创建static服务
} registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() { //创建独立的对象 用于LayoutInflater
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
}});
/*package*/ static class ServiceFetcher {
int mContextCacheIndex = -1;
/**
* Main entrypoint; only override if you don't need caching.
*/
public Object getService(ContextImpl ctx) {// ContextImpl实例。
ArrayList<Object> cache = ctx.mServiceCache;
Object service;
synchronized (cache) {
if (cache.size() == 0) {
// Initialize the cache vector on first access.
// At this point sNextPerContextServiceCacheIndex
// is the number of potential services that are
// cached per-Context.
for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
cache.add(null);
}
} else {
service = cache.get(mContextCacheIndex);//获取缓存是否存在
if (service != null) {
return service;
}
}
service = createService(ctx); //用来缓存服务实例
cache.set(mContextCacheIndex, service);
return service;
}
}
/**
* Override this to create a new per-Context instance of the
* service. getService() will handle locking and caching.
*/
public Object createService(ContextImpl ctx) {
throw new RuntimeException("Not implemented");
}
}
com.android.internal.policy.PolicyManager
找到了LayoutInflater的实现类 这个类算是个代理类 本质上是
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy"; policy\src\com\android\internal\policy\impl 目录下 public LayoutInflater makeNewLayoutInflater(Context context) {
return new PhoneLayoutInflater(context); //实例化
} policy\src\com\android\internal\policy\impl\PhoneLayoutInflater 回到LayoutInflater 递归解析XML 使用的是XMl Pull Parser解析器 public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { }
rInflate开始递归 都是XML解析
void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else if (TAG_1995.equals(name)) {
final View view = new BlinkLayout(mContext, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
viewGroup.addView(view, params);
} else {
final View view = createViewFromTag(parent, name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
viewGroup.addView(view, params);
}
}
if (finishInflate) parent.onFinishInflate();//解析完了,这个方法我们自定义可以复写 可以会去掉 子View的信息
}
基本上布局都是ViewGroup的子类 里面都有child view, 我们常用的findViewById 就是遍历去找对应ID的View
public final View findViewById(int id) {
if (id < 0) {
return null;
}
return findViewTraversal(id);
}
直接看ViewGroup中的findViewTraversal @Override
protected View findViewTraversal(int id) {
if (id == mID) { //等于自己
return this;
} final View[] where = mChildren;
final int len = mChildrenCount; for (int i = 0; i < len; i++) {
View v = where[i]; if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) { //IS_ROOT_NAMESPACE 可能是查询到最后一层了(猜的) 然后再遍历 查询
v = v.findViewById(id); if (v != null) {
return v;
}
}
} return null;
}
如果布局层级太深 解析XML和查找View都是耗费CPU的,所以做项目过程中 有必要进行布局优化。
本文源码: 4.1
Android LayoutInflater和findViewById 源码详解的更多相关文章
- Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解
Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解 今天主要理一下StreamingContext的启动过程,其中最为重要的就是Jo ...
- spring事务详解(三)源码详解
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- 条件随机场之CRF++源码详解-预测
这篇文章主要讲解CRF++实现预测的过程,预测的算法以及代码实现相对来说比较简单,所以这篇文章理解起来也会比上一篇条件随机场训练的内容要容易. 预测 上一篇条件随机场训练的源码详解中,有一个地方并没有 ...
- [转]Linux内核源码详解--iostat
Linux内核源码详解——命令篇之iostat 转自:http://www.cnblogs.com/york-hust/p/4846497.html 本文主要分析了Linux的iostat命令的源码, ...
- saltstack源码详解一
目录 初识源码流程 入口 1.grains.items 2.pillar.items 2/3: 是否可以用python脚本实现 总结pillar源码分析: @(python之路)[saltstack源 ...
- Shiro 登录认证源码详解
Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...
- udhcp源码详解(五) 之DHCP包--options字段
中间有很长一段时间没有更新udhcp源码详解的博客,主要是源码里的函数太多,不知道要不要一个一个讲下去,要知道讲DHCP的实现理论的话一篇博文也就可以大致的讲完,但实现的源码却要关心很多的问题,比如说 ...
- Activiti架构分析及源码详解
目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...
- 源码详解系列(六) ------ 全面讲解druid的使用和源码
简介 druid是用于创建和管理连接,利用"池"的方式复用连接减少资源开销,和其他数据源一样,也具有连接数控制.连接可靠性测试.连接泄露控制.缓存语句等功能,另外,druid还扩展 ...
随机推荐
- ASP.NET关于引用bootstrap.css导致Gridview Header无法居中
HorizontalAlign="Center" 属性因不知名原因被覆盖掉. 可以使用<HeaderStyle CssClass="text-center&qu ...
- frameset iframe用来分页
frameset用来分大的框架 iframe用来在frame分框架之后,内嵌分割. <FRAMESET border=1 frameSpacing=1 borderColor=#47478d r ...
- 检查网口流量与前10名流量大IP
此脚本包含的功能有: 1.实时监控任意网卡的流量 2.统计10秒内平均流量 3.统计每个端口在10秒内的平均流量,基于客户端和服务端端口统计.可以看出哪些端口占流量比较大,对于web服务器,一般是80 ...
- c#分支语句;循环语句(随堂练习)
1. 输入月份,日期号,输出是今年的第几天 平年,2月28天 switch (变量名) {case "": break} 2. 循环语句: for(int i ...
- Java NIO API详解
在JDK 1.4以前,Java的IO操作集中在java.io这个包中,是基于流的同步(blocking)API.对于大多数应用来说,这样的API使用很方便,然而,一些对性能要求较高的应用,尤其是服务端 ...
- Linux系统下用户行为审计
以下内容在RHEL 6.4下测试通过. 1.编写脚本Command_history.sh,生产历史命令记录文件,内容如下 #!/bin/bash [ -d /usr/lib/.cmdlog ] || ...
- 数据结构(树链剖分):COGS 2109. [NOIP2015] 运输计划
2109. [NOIP2015] 运输计划 ★★★ 输入文件:transport.in 输出文件:transport.out 简单对比时间限制:1 s 内存限制:256 MB [题目描 ...
- NOI题库2454 雷涛的小猫
2454:雷涛的小猫 总时间限制: 20000ms 单个测试点时间限制: 10000ms 内存限制: 65536kB 描述 雷涛同学非常的有爱心,在他的宿舍里,养着一只因为受伤被救助的小猫(当然,这样 ...
- jsp中的contentType与pageEncoding的区别和作用
jsp中的contentType与pageEncoding的区别和作用 <%@ page contentType="text/html; charset=utf-8" p ...
- javascript随机将第一个dom中的图片添加到第二个div中去
javascript随机将第一个dom中的图片添加到第二个div中去,此代码的是一个简单的例子,将第一个div中的五张图片中,提取随机两张显示到第二个div中. <!DOCTYPE html P ...