LayoutInflater#inflate 解析

LayoutInflater 是系统提供的一个解析工具,用于将布局XML文件实例化为其相应的 View 对象。

调用流程

LayoutInflater 有个多个重载的inflate 方法:

android.view.LayoutInflater#inflate(int, android.view.ViewGroup)
android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)
android.view.LayoutInflater#inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup)
android.view.LayoutInflater#inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean)

最后都会执行到 android.view.LayoutInflater#inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean) 方法内。
另外android.view.View#inflate 最终也是调用的LayoutInflater的inflater 方法
在这里插入图片描述
附一个整体的调用流程图
在这里插入图片描述

源码分析

比较常用的是
android.view.LayoutInflater#inflate(int, android.view.ViewGroup)
android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)
这两个方法,那么这个root 是干嘛的,attachToRoot 的作用是啥?我们从源码中去寻找答案。
(*注:sdk版本为28)

/**
 1. 将 xml节点解析成一个view 对象
 2. <p>
 3.  4. @param parser XML dom node containing the description of the view
 5.        hierarchy.
 6. @param root 根view,如果attachToRoot 为true,则将xml 解析得到的view 添加到此view 上。
          如果false,则为xml解析得到的view 提供LayoutParams,并不会附加到该view 上。
 7. @param attachToRoot 是否将xml 解析得到的view 添加到root view上。
          如果为false,则root view 仅用作为xml 中的顶视图创建LayoutParmas。
 8. @return 如果提供的 root 不为null 并且attachToRoot为true,则返回 root;否则返回解析xml得到的根view。
 */
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        // --忽略 解析相关 代码--
        
        View result = root;

        try {
            // --忽略 解析相关 代码--

            final String name = parser.getName();

            // --忽略 debug 代码--

            // merge 标签,继续向下递归解析
            if (TAG_MERGE.equals(name)) {
                // merge 标签必须有root,并attachToRoot为true,否则抛异常
                if (root == null || !attachToRoot) {
                    throw new InflateException("<merge /> can be used only with a valid "
                            + "ViewGroup root and attachToRoot=true");
                }
                // 递归方法,用于向下延伸xml层次结构并实例化视图、实例化其子视图
                rInflate(parser, root, inflaterContext, attrs, false);
            } else {
                // 找出xml中的根view,赋给temp。注意,此根视图和root 不是同一个!
                final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                ViewGroup.LayoutParams params = null;

                if (root != null) {
                    // -- 忽略debug 代码
                    
                    // 创建root 的LayoutParams
                    params = root.generateLayoutParams(attrs);
                    if (!attachToRoot) {
                        // 如果 attachToRoot为false,给temp 设置layoutParams。                     
                        temp.setLayoutParams(params);
                    }
                }
                
                // -- 忽略debug 代码

                // 解析temp 下的所有子视图
                rInflateChildren(parser, temp, attrs, true);
                
                // -- 忽略debug 代码

                // 如果设置了root 并且attachToRoot 为 true,则添加view 到根视图
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }

                // 如果root 为空或者 attachToRoot为false,返回在xml中找到的顶视图。否则返回传入的根视图。
                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }

        } catch (XmlPullParserException e) {
            final InflateException ie = new InflateException(e.getMessage(), e);
            ie.setStackTrace(EMPTY_STACK_TRACE);
            throw ie;
        } catch (Exception e) {
            final InflateException ie = new InflateException(parser.getPositionDescription()
                    + ": " + e.getMessage(), e);
            ie.setStackTrace(EMPTY_STACK_TRACE);
            throw ie;
        } finally {
            // Don't retain static reference on context.
            mConstructorArgs[0] = lastContext;
            mConstructorArgs[1] = null;

            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }

        return result;
    }
}

简单总结下流程:

  1. 通过XmlPullParser 解析xml 布局,获取布局中的根视图 temp;
  2. 根据 root 是否为null 来决定是否为temp 创建LayoutParams;
  3. 根据 root 是否为null 及 attachToRoot 是否为true 来决定是否将 temp 添加到root 上;
  4. 返回正确的view。如果temp 成功添加到root 上,返回 root;否则返回temp。
发布了22 篇原创文章 · 获赞 44 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/JM_beizi/article/details/105364933
今日推荐