Android 视图优化merge标签分析

来源:互联网 发布:win10系统里面装mac 编辑:程序博客网 时间:2024/06/08 05:39


当在布局文件中复用另外的布局时, <merge />标签能够在布局层次消除多余的视图元素。


当我们使用了<merge/> 标签后系统会做哪些操作呢?


来看源码:

系统将xml布局转换成view对象经历以下方法:

当调用:View.inflate(context, resource, root)   时:

    public static View inflate(Context context, int resource, ViewGroup root) {        LayoutInflater factory = LayoutInflater.from(context);        return factory.inflate(resource, root);    }


继续调用inflate:

public View inflate(int resource, ViewGroup root) {        return inflate(resource, root, root != null);    }
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {        final Resources res = getContext().getResources();        if (DEBUG) {            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("                    + Integer.toHexString(resource) + ")");        }        final XmlResourceParser parser = res.getLayout(resource);        try {            return inflate(parser, root, attachToRoot);        } finally {            parser.close();        }    }

已经出现 XmlResoureParser 了,继续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)) { //!!!!注意这里是merge标签,                    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, false);//执行merge                } else {                    // Temp is the root view that was found in the xml                    final View temp = createViewFromTag(root, name, attrs, false);                    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, 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时,遇到了merge标签:调用  rInflate(parser, root, attrs, false, false);

同时也注意到 merge的必须是ViewGroup  attachToRoot=true


 void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,            boolean finishInflate, boolean inheritContext) 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_TAG.equals(name)) {                parseViewTag(parser, parent, attrs);            } else if (TAG_INCLUDE.equals(name)) {                if (parser.getDepth() == 0) {                    throw new InflateException("<include /> cannot be the root element");                }                parseInclude(parser, parent, attrs, inheritContext);            } else if (TAG_MERGE.equals(name)) {//merge也不能是 非root元素                throw new InflateException("<merge /> must be the root element");            } else {                final View view = createViewFromTag(parent, name, attrs, inheritContext);                final ViewGroup viewGroup = (ViewGroup) parent;                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);                rInflate(parser, view, attrs, true, true);                viewGroup.addView(view, params);            }        }        if (finishInflate) parent.onFinishInflate();    }

来到: final View view = createViewFromTag(parent, name, attrs, inheritContext);



View createViewFromTag(View parent, String name, AttributeSet attrs, boolean inheritContext) {        if (name.equals("view")) {            name = attrs.getAttributeValue(null, "class");        }        Context viewContext; //这里<span style="font-family: 'Comic Sans MS';">inheritContext为false,注意viewContext的值</span>        if (parent != null && inheritContext) {            viewContext = parent.getContext();        } else {             viewContext = mContext;        }        // Apply a theme wrapper, if requested. //获取xml里定义的属性        final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME);        final int themeResId = ta.getResourceId(0, 0);        if (themeResId != 0) {            viewContext = new ContextThemeWrapper(viewContext, themeResId);        }        ta.recycle();        if (name.equals(TAG_1995)) {            // Let's party like it's 1995! 这是什么注释??            return new BlinkLayout(viewContext, attrs);        }        if (DEBUG) System.out.println("******** Creating view: " + name);        try {            View view;            if (mFactory2 != null) {                view = mFactory2.onCreateView(parent, name, viewContext, attrs);            } else if (mFactory != null) {                view = mFactory.onCreateView(name, viewContext, attrs);            } else {                view = null;            }            if (view == null && mPrivateFactory != null) {                view = mPrivateFactory.onCreateView(parent, name, viewContext, attrs);            }            if (view == null) {                final Object lastContext = mConstructorArgs[0];                mConstructorArgs[0] = viewContext;                try {                    if (-1 == name.indexOf('.')) {                        view = onCreateView(parent, name, attrs);                    } else {                        view = createView(name, null, attrs);                    }                } finally {                    mConstructorArgs[0] = lastContext;                }            }            if (DEBUG) System.out.println("Created view is: " + view);            return view;        } catch (InflateException e) {            throw e;        } catch (ClassNotFoundException e) {            InflateException ie = new InflateException(attrs.getPositionDescription()                    + ": Error inflating class " + name);            ie.initCause(e);            throw ie;        } catch (Exception e) {            InflateException ie = new InflateException(attrs.getPositionDescription()                    + ": Error inflating class " + name);            ie.initCause(e);            throw ie;        }    }





0 0