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