美文网首页
layoutinflater.inflate源码详解

layoutinflater.inflate源码详解

作者: wcwmyzy | 来源:发表于2020-06-11 11:18 被阅读0次

    加载布局的两种方式
    View.inflate(context,R.layout.xxx,viewGroup);
    LayoutInflater.from(this).inflate(R.layout.xxx,viewGroup,true);
    View.infalte内部也是调用LayoutInflater.inflate

    public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
            //通过Context获取了一个 LayoutInflater对象
            LayoutInflater factory = LayoutInflater.from(context);
            //调用LayoutInflater.inflate方法
            return factory.inflate(resource, root);
        }
    

    那么 LayoutInflater.inflate是怎么加载布局的呢
    首先 我们先看一下LayoutInflater.inflate重载 主要是两个要注意的
    public View inflate(XmlPullParser parser, @Nullable ViewGroup root)
    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)
    其他都是后面两个参数不一样而已
    我们看到一个是XmlPullParser对象 和我们的布局id两个重载方法,但是在 LayoutInflater 内部其实都是调的同一个方法
    比如我们如果传的是布局id 那么LayoutInflater会给我们自动创建一个XmlPullParser对象

    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
            final Resources res = getContext().getResources();
            if (DEBUG) {
                Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                        + Integer.toHexString(resource) + ")");
            }
            //=========================在这里通过我们传进来的布局id(resource) 初始化了一个XmlResourceParser=========================
            final XmlResourceParser parser = res.getLayout(resource);
            try {
                //=================其他的方法最终都会调用这个方法加载布局==========================
                return inflate(parser, root, attachToRoot);
            } finally {
                parser.close();
            }
        }
    

    接下来我们一行一行分析源码 日志打印之类的跳过

    该方法声明
    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

    首先开启了线程锁 不知道的自行搜索
    synchronized (mConstructorArgs)

                //获取Context 
                final Context inflaterContext = mContext;
                //获取布局的属性 比如高度 宽度 然后在createViewFromTag()方法中对View的属性初始化
                final AttributeSet attrs = Xml.asAttributeSet(parser);
                //不知道有啥用 知道的可以告知一下
                Context lastContext = (Context) mConstructorArgs[0];
                mConstructorArgs[0] = inflaterContext;
                //声明一个 View 默认将传进来的ViewGroup赋值给 result 后面作为返回值返回
                View result = root;
    

    主要是判断布局是不是空的 能不能解析 细节不用太关心

                    // Look for the root node.
                    int type;
                    while ((type = parser.next()) != XmlPullParser.START_TAG &&
                            type != XmlPullParser.END_DOCUMENT) {
                        // Empty
                    }
    

    判断是不是有开始标签 没有抛异常

                    if (type != XmlPullParser.START_TAG) {
                        throw new InflateException(parser.getPositionDescription()
                                + ": No start tag found!");
                    }
    

    这句比较重要 获取根布局的名称 主要是后面判断根布局是不是merge

    final String name = parser.getName();
    

    判断根布局是不是merge标签 传进来的ViewGroup为空 或者attachToRoot为false的话抛异常

    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(XmlPullParser parser, View parent, Context context,AttributeSet attrs, boolean finishInflate)
        //解析布局并创建View 感兴趣的可以自己看一下
        rInflate(parser, root, inflaterContext, attrs, false);
    }
    

    如果根布局不是merge

                else {
                        //创建一个临时的View
                        final View temp = createViewFromTag(root, name, inflaterContext, attrs);
                        //声明LayoutParams
                        ViewGroup.LayoutParams params = null;
                        
                        //判断ViewGroup是否等于空
                        if (root != null) {
                            //通过generateLayoutParams(attrs)初始化LayoutParams
                            //方法内部其实是通过解析自定义属性一样 解析了attrs中的高度和宽度
                            //TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
                            params = root.generateLayoutParams(attrs);
                            if (!attachToRoot) {
                                
                                //如果attachToRoot为false 就不会将创建的View(---->temp)添加到
                                //我们传进来的ViewGroup(---->root)中 只设置View 的LayoutParams
                                temp.setLayoutParams(params);
                            }
                        }
    
                        //初始化所有View(--->temp)下的所有子View 并将解析的子View添加到View(---->temp)中
                        rInflateChildren(parser, temp, attrs, true);
                        
                        //=====================================================================  
                        //如果传进来的ViewGroup不为空 并且 attachToRoot为true 就自动将View(--->temp)添加到
                        //我们传进来的ViewGroup(---->root)中
                        //=====================================================================
                        if (root != null && attachToRoot) {
                            root.addView(temp, params);
                        }
                        //如果ViewGroup为空 或者 attachToRoot为空 将创建的View(--->temp)赋值给 result变量
                        if (root == null || !attachToRoot) {
                            result = temp;
                        }
                    }
    
    //返回创建好的View对象
    return result;
    

    完毕

    相关文章

      网友评论

          本文标题:layoutinflater.inflate源码详解

          本文链接:https://www.haomeiwen.com/subject/hdbvtktx.html