 
本文转载自微信公众号「Android开发编程」,探究作者Android开发编程。源码原理转载本文请联系Android开发编程公众号。布局 前言在开发中,解析对于 LayoutInflater 的探究 inflate() 方法,它的源码原理作用是把 xml 布局转换为对应的 View 对象,我们几乎天天在用; 今天我们就来分析讲解下; 一、布局什么是解析LayoutInflater?LayoutInflater 的作用就是将XML布局文件实例化为相应的 View 对象,需要通过Activity.getLayoutInflater() 或 Context.getSystemService(Class) 来获取与当前Context已经关联且正确配置的探究标准LayoutInflater; @SystemService(Context.LAYOUT_INFLATER_SERVICE) public abstract class LayoutInflater {     ... }         获取LayoutInflater 1、 View.inflate(...)public static View inflate(Context context,源码原理 @LayoutRes int resource, ViewGroup root) {     LayoutInflater factory = LayoutInflater.from(context);     return factory.inflate(resource, root); }         2、Activity#getLayoutInflater()Activity.class的布局源代码: public class Activity extends .......  { .........  @NonNull     public LayoutInflater getLayoutInflater() {         return getWindow().getLayoutInflater();     } .........  @NonNull     public LayoutInflater getLayoutInflater() {         return getWindow().getLayoutInflater();     } .........    final void attach(.....){           ......            mWindow = new PhoneWindow(this, window, activityConfigCallback);           .......     } ......... } PhoneWindow源码:    public PhoneWindow(Context context) {         super(context);         mLayoutInflater = LayoutInflater.from(context);     }         3、PhoneWindow#getLayoutInflater()private LayoutInflater mLayoutInflater; public PhoneWindow(Context context) {     super(context);     mLayoutInflater = LayoutInflater.from(context); } public LayoutInflater getLayoutInflater() {     return mLayoutInflater; }         4、解析LayoutInflater#from(Context)@SystemService(Context.LAYOUT_INFLATER_SERVICE) public abstract class LayoutInflater {  .....  /**      * Obtains the LayoutInflater from the given context.      */     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;     } ..... }         二、探究源码分析 
 1、源码原理LayoutInflater#inflate(...)调用inflate()进行布局解析 public View inflate(@LayoutRes int resource,布局 @Nullable ViewGroup root, boolean attachToRoot) {     final Resources res = getContext().getResources();     1. 解析预编译的布局     View view = tryInflatePrecompiled(resource, res, root, attachToRoot);     if (view != null) {         return view;     }     2. 构造 XmlPull 解析器      XmlResourceParser parser = res.getLayout(resource);     try {     3. 执行解析         return inflate(parser, root, attachToRoot);     } finally {         parser.close();     } }         tryInflatePrecompiled(...)是解析预编译的高防服务器布局;        构造 XmlPull 解析器 XmlResourceParser        执行解析,是解析的主流程        2、inflatepublic View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {     1. 结果变量     View result = root;     2. 最外层的标签     final String name = parser.getName();     3. <merge>     if (TAG_MERGE.equals(name)) {         3.1 异常         if (root == null || !attachToRoot) {             throw new InflateException("<merge /> can be used only with a valid "                 + "ViewGroup root and attachToRoot=true");         }         3.2 递归执行解析         rInflate(parser, root, inflaterContext, attrs, false);     } else {         4.1 创建最外层 View         final View temp = createViewFromTag(root, name, inflaterContext, attrs);         ViewGroup.LayoutParams params = null;         if (root != null) {             4.2 创建匹配的 LayoutParams             params = root.generateLayoutParams(attrs);             if (!attachToRoot) {                 4.3 如果 attachToRoot 为 false,设置LayoutParams                 temp.setLayoutParams(params);             }         }         5. 以 temp 为 root,递归执行解析         rInflateChildren(parser, temp, attrs, true);         6. attachToRoot 为 true,addView()         if (root != null && attachToRoot) {             root.addView(temp, params);         }         7. root 为空 或者 attachToRoot 为 false,返回 temp         if (root == null || !attachToRoot) {             result = temp;         }     }     return result; } -> 3.2 void rInflate(XmlPullParser parser, View parent, Context context, AttributeSet attrs, boolean finishInflate) {     while(parser 未结束) {         if (TAG_INCLUDE.equals(name)) {             1) <include>             if (parser.getDepth() == 0) {                 throw new InflateException("<include /> cannot be the root element");             }             parseInclude(parser, context, parent, attrs);         } else if (TAG_MERGE.equals(name)) {             2) <merge>             throw new InflateException("<merge /> must be the root element");         } else {             3) 创建 View              final View view = createViewFromTag(parent, name, context, attrs);             final ViewGroup viewGroup = (ViewGroup) parent;             final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);             4) 递归             rInflateChildren(parser, view, attrs, true);             5) 添加到视图树             viewGroup.addView(view, params);         }     } } -> 5. 递归执行解析 final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,             boolean finishInflate) throws XmlPullParserException, IOException {     rInflate(parser, parent, parent.getContext(), attrs, finishInflate); } 3、createViewFromTag createViewFromTag(),它负责由 <tag> 创建 View 对象     View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,             boolean ignoreThemeAttr) {         if (name.equals("view")) {             name = attrs.getAttributeValue(null, "class");         }         // Apply a theme wrapper, if allowed and one is specified.         if (!ignoreThemeAttr) {             final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);             final int themeResId = ta.getResourceId(0, 0);             if (themeResId != 0) {                 context = new ContextThemeWrapper(context, themeResId);             }             ta.recycle();         }         if (name.equals(TAG_1995)) {             // Lets party like its 1995!             return new BlinkLayout(context, attrs);         }         try {             View view;             if (mFactory2 != null) {                 // ① 有mFactory2,则调用mFactory2的onCreateView方法                 view = mFactory2.onCreateView(parent, name, context, attrs);             } else if (mFactory != null) {                 // ② 有mFactory,则调用mFactory的onCreateView方法                 view = mFactory.onCreateView(name, context, attrs);             } else {                 view = null;             }             if (view == null && mPrivateFactory != null) {                 // ③ 有mPrivateFactory,则调用mPrivateFactory的onCreateView方法                 view = mPrivateFactory.onCreateView(parent, name, context, attrs);             }             if (view == null) {                 // ④ 走到这步说明三个Factory都没有,则开始自己创建View                 final Object lastContext = mConstructorArgs[0];                 mConstructorArgs[0] = context;                 try {                     if (-1 == name.indexOf(.)) {                         // ⑤ 如果View的name中不包含 . 则说明是系统控件,会在接下来的调用链在name前面加上 android.view.                         view = onCreateView(parent, name, attrs);                     } else {                         // ⑥ 如果name中包含 . 则直接调用createView方法,onCreateView 后续也是调用了createView                         view = createView(name, null, attrs);                     }                 } finally {                     mConstructorArgs[0] = lastContext;                 }             }             return view;         } catch (InflateException e) {             throw e;         }      }         createViewFromTag 方法比较简单,服务器租用首先尝试通过 Factory 来创建View;        如果没有 Factory 的话则通过 createView 来创建View;        3、createView 方法解析public final View createView(String name, String prefix, AttributeSet attrs)             throws ClassNotFoundException, InflateException {         Constructor<? extends View> constructor = sConstructorMap.get(name);         if (constructor != null && !verifyClassLoader(constructor)) {             constructor = null;             sConstructorMap.remove(name);         }         Class<? extends View> clazz = null;         try {             Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);             if (constructor == null) {                 // Class not found in the cache, see if its real, and try to add it                 clazz = mContext.getClassLoader().loadClass(                         prefix != null ? (prefix + name) : name).asSubclass(View.class);                 if (mFilter != null && clazz != null) {                     boolean allowed = mFilter.onLoadClass(clazz);                     if (!allowed) {                         failNotAllowed(name, prefix, attrs);                     }                 }                 // ① 反射获取这个View的构造器                 constructor = clazz.getConstructor(mConstructorSignature);                 constructor.setAccessible(true);                 // ② 缓存构造器                 sConstructorMap.put(name, constructor);             } else {                 // If we have a filter, apply it to cached constructor                 if (mFilter != null) {                     // Have we seen this name before?                     Boolean allowedState = mFilterMap.get(name);                     if (allowedState == null) {                         // New class -- remember whether it is allowed                         clazz = mContext.getClassLoader().loadClass(                                 prefix != null ? (prefix + name) : name).asSubclass(View.class);                         boolean allowed = clazz != null && mFilter.onLoadClass(clazz);                         mFilterMap.put(name, allowed);                         if (!allowed) {                             failNotAllowed(name, prefix, attrs);                         }                     } else if (allowedState.equals(Boolean.FALSE)) {                         failNotAllowed(name, prefix, attrs);                     }                 }             }             Object lastContext = mConstructorArgs[0];             if (mConstructorArgs[0] == null) {                 // Fill in the context if not already within inflation.                 mConstructorArgs[0] = mContext;             }             Object[] args = mConstructorArgs;             args[1] = attrs;             // ③ 使用反射创建 View 对象,这样一个 View 就被创建出来了             final View view = constructor.newInstance(args);             if (view instanceof ViewStub) {                 // Use the same context when inflating ViewStub later.                 final ViewStub viewStub = (ViewStub) view;                 viewStub.setLayoutInflater(cloneInContext((Context) args[0]));             }             mConstructorArgs[0] = lastContext;             return view;         } catch (ClassCastException e) {         }      }         createView 方法也比较简单,通过反射来创建的 View 对象;  
 4、 Factory2 接口Factory2可以拦截实例化 View 的步骤,在 LayoutInflater 中有两个方法可以设置: 方法1: public void setFactory2(Factory2 factory) {     if (mFactorySet) {         关注点:禁止重复设置         throw new IllegalStateException("A factory has already been set on this LayoutInflater");     }     if (factory == null) {         throw new NullPointerException("Given factory can not be null");     }     mFactorySet = true;     if (mFactory == null) {         mFactory = mFactory2 = factory;     } else {         mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2);     } }         方法2 @hide public void setPrivateFactory(Factory2 factory) {     if (mPrivateFactory == null) {         mPrivateFactory = factory;     } else {         mPrivateFactory = new FactoryMerger(factory, factory, mPrivateFactory, mPrivateFactory);     } }         使用 setFactory2() 和 setPrivateFactory() 可以设置 Factory2 接口(拦截器),其中同一个 LayoutInflater 的setFactory2()不能重复设置,setPrivateFactory() 是 hide 方法; 总结通过 XML 的 Pull 解析方式获取 View 的标签;        通过标签以反射的方式来创建 View 对象;        如果是 ViewGroup 的话则会对子 View 遍历并重复以上步骤,然后 add 到父 View 中;        与之相关的几个方法:inflate ——》 rInflate ——》 createViewFromTag ——》 createView ;        Factory2 是一个很实用的接口,需要掌握通过 setFactory2() 拦截布局解析的技巧; |