• LayoutInflater源码分析


    大家都很熟悉LayoutInflater来添加View。我们看一下它的实现。

    public abstract class LayoutInflater {}

    首先LayoutInflater是个抽象类,也没有继承其他类.

    1.我们可以通过下面两种方式获得LayoutInflater;

    LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    或者Activity.getLayoutInflater();

    2.一般使用LayoutInflater的方式是以下几种

     public View inflate(int resource, ViewGroup root, boolean attachToRoot)
    public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
    public View inflate(int resource, ViewGroup root)
    public View inflate(XmlPullParser parser, ViewGroup root)

    其中加载xml分R.id.xx和直接载入.xml,但是由于解析xml需要时间,这时如果xml不是预先被编译就不能显示视图报错(如在加载assets文件中的xml文件).使用R.id.xx实际上也是通过XmlPullParser来加载视图的.

    ViewGroup相当于父视图,如果有root视图,默认attachToRoot为false,这时会messure父视图的layout来加载子视图.如果root视图为空,会创建视图来加载到viewtree的根部.其实创建的是内部类BlinkLayout,它是继承帧视图,方便上下图层的叠加.在加载BlinkLayout之前还是先创建了

    ViewStub,来占空视图.

    private static class BlinkLayout extends FrameLayout 

    下面我们看下最关键的inflate

      public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
            synchronized (mConstructorArgs) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
    
                final AttributeSet attrs = Xml.asAttributeSet(parser);
                Context lastContext = (Context)mConstructorArgs[0];
                mConstructorArgs[0] = mContext;
                View result = root;
    
                try {
                    // 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!");
                    }
    
                    final String name = parser.getName();
                    
                    if (DEBUG) {
                        System.out.println("**************************");
                        System.out.println("Creating root view: "
                                + name);
                        System.out.println("**************************");
                    }
    
                    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(parser, root, attrs, false);
                    } else {
                        // Temp is the root view that was found in the xml
                        View temp;
                        if (TAG_1995.equals(name)) {
                            temp = new BlinkLayout(mContext, attrs);
                        } else {
                            temp = createViewFromTag(root, name, attrs);
                        }
    
                        ViewGroup.LayoutParams params = null;
    
                        if (root != null) {
                            if (DEBUG) {
                                System.out.println("Creating params from root: " +
                                        root);
                            }
                            // Create layout params that match root, if supplied
                            params = root.generateLayoutParams(attrs);
                            if (!attachToRoot) {
                                // Set the layout params for temp if we are not
                                // attaching. (If we are, we use addView, below)
                                temp.setLayoutParams(params);
                            }
                        }
    
                        if (DEBUG) {
                            System.out.println("-----> start inflating children");
                        }
                        // Inflate all children under temp
                        rInflate(parser, temp, attrs, true);
                        if (DEBUG) {
                            System.out.println("-----> done inflating children");
                        }
    
                        // We are supposed to attach all the views we found (int temp)
                        // to root. Do that now.
                        if (root != null && attachToRoot) {
                            root.addView(temp, params);
                        }
    
                        // Decide whether to return the root that was passed in or the
                        // top view found in xml.
                        if (root == null || !attachToRoot) {
                            result = temp;
                        }
                    }
    
                } catch (XmlPullParserException e) {
                    InflateException ex = new InflateException(e.getMessage());
                    ex.initCause(e);
                    throw ex;
                } catch (IOException e) {
                    InflateException ex = new InflateException(
                            parser.getPositionDescription()
                            + ": " + e.getMessage());
                    ex.initCause(e);
                    throw ex;
                } finally {
                    // Don't retain static reference on context.
                    mConstructorArgs[0] = lastContext;
                    mConstructorArgs[1] = null;
                }
    
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    
                return result;
            }
        }

    它在解析xml时候实际是调用了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();
        }

    解析的是一下xml的标签

        private static final String TAG_MERGE = "merge";
        private static final String TAG_INCLUDE = "include";
        private static final String TAG_1995 = "blink";
        private static final String TAG_REQUEST_FOCUS = "requestFocus";

    我们在xml中引用其他视图的时候会用到<include>来减少重复视图的编写.

    我们在parseInclude中可以看到解析不同的tag执行不同的操作.其中requestFocus标签目前还没有做任何事情.

     private void parseInclude(XmlPullParser parser, View parent, AttributeSet attrs)
                throws XmlPullParserException, IOException {
    
            int type;
    
            if (parent instanceof ViewGroup) {
                final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
                if (layout == 0) {
                    final String value = attrs.getAttributeValue(null, "layout");
                    if (value == null) {
                        throw new InflateException("You must specifiy a layout in the"
                                + " include tag: <include layout="@layout/layoutID" />");
                    } else {
                        throw new InflateException("You must specifiy a valid layout "
                                + "reference. The layout ID " + value + " is not valid.");
                    }
                } else {
                    final XmlResourceParser childParser =
                            getContext().getResources().getLayout(layout);
    
                    try {
                        final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
    
                        while ((type = childParser.next()) != XmlPullParser.START_TAG &&
                                type != XmlPullParser.END_DOCUMENT) {
                            // Empty.
                        }
    
                        if (type != XmlPullParser.START_TAG) {
                            throw new InflateException(childParser.getPositionDescription() +
                                    ": No start tag found!");
                        }
    
                        final String childName = childParser.getName();
    
                        if (TAG_MERGE.equals(childName)) {
                            // Inflate all children.
                            rInflate(childParser, parent, childAttrs, false);
                        } else {
                            final View view = createViewFromTag(parent, childName, childAttrs);
                            final ViewGroup group = (ViewGroup) parent;
    
                            // We try to load the layout params set in the <include /> tag. If
                            // they don't exist, we will rely on the layout params set in the
                            // included XML file.
                            // During a layoutparams generation, a runtime exception is thrown
                            // if either layout_width or layout_height is missing. We catch
                            // this exception and set localParams accordingly: true means we
                            // successfully loaded layout params from the <include /> tag,
                            // false means we need to rely on the included layout params.
                            ViewGroup.LayoutParams params = null;
                            try {
                                params = group.generateLayoutParams(attrs);
                            } catch (RuntimeException e) {
                                params = group.generateLayoutParams(childAttrs);
                            } finally {
                                if (params != null) {
                                    view.setLayoutParams(params);
                                }
                            }
    
                            // Inflate all children.
                            rInflate(childParser, view, childAttrs, true);
    
                            // Attempt to override the included layout's android:id with the
                            // one set on the <include /> tag itself.
                            TypedArray a = mContext.obtainStyledAttributes(attrs,
                                com.android.internal.R.styleable.View, 0, 0);
                            int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
                            // While we're at it, let's try to override android:visibility.
                            int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
                            a.recycle();
    
                            if (id != View.NO_ID) {
                                view.setId(id);
                            }
    
                            switch (visibility) {
                                case 0:
                                    view.setVisibility(View.VISIBLE);
                                    break;
                                case 1:
                                    view.setVisibility(View.INVISIBLE);
                                    break;
                                case 2:
                                    view.setVisibility(View.GONE);
                                    break;
                            }
    
                            group.addView(view);
                        }
                    } finally {
                        childParser.close();
                    }
                }
            } else {
                throw new InflateException("<include /> can only be used inside of a ViewGroup");
            }
    
            final int currentDepth = parser.getDepth();
            while (((type = parser.next()) != XmlPullParser.END_TAG ||
                    parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
                // Empty
            }
        }
  • 相关阅读:
    md转html,并带目录结构
    vue05
    vue04
    mysql索引及调优
    mysql的锁与事务
    python基本数据类型的操作
    redis集群
    docker 学习(四)
    MongoDB基本操作
    MongoDB基础
  • 原文地址:https://www.cnblogs.com/hxy0107/p/4892457.html
Copyright © 2020-2023  润新知