代码改变世界

LayoutInflater 学习

2013-06-15 23:18  ...平..淡...  阅读(348)  评论(0编辑  收藏  举报
LayoutInflater类
作用:实例化一个布局XML文件到其相应的视图对象。
Instantiates a layout XML file into its corresponding View objects. It is never used directly. Instead, usegetLayoutInflater() or getSystemService(String) to retrieve a standard LayoutInflater instance that is already hooked up to the current context and correctly configured for the device you are running on.
 
通俗的说,inflate就相当于将一个xml中定义的布局找出来。
因为在一个Activity里如果直接用findViewById()的话,对应的是setConentView()的那个layout里的组件。
因此如果你的Activity里如果用到别的layout,比如对话框上的layout,你还要设置对话框上的layout里的组件(像图片ImageView,文字TextView)上的内容,你就必须用inflate()先将对话框上的layout找出来,然后再用这个layout对象去找到它上面的组件。

  

一般有三个方式创建LayoutInflater类
1. LayoutInflater inflater = getLayoutInflater();  //调用Activity的getLayoutInflater()

2. LayoutInflater inflater = LayoutInflater.from(context);   
 
3. LayoutInflater localinflater =  (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

 

其实三个方式实质上是一样的,下面通过getLayoutInflater()方法来进行分析

 

 
(1)Activity中的getLayoutInflater()方法其实就是调用PhoneWindow的getLayoutInflater()方法:
Activity.java::getLayoutInflater()
/**
 * Convenience for calling
 * {@link android.view.Window#getLayoutInflater}.
 */
 public LayoutInflater getLayoutInflater() {
     return getWindow().getLayoutInflater();
 }
PhoneWindow.java::getLayoutInflater()
/**
 * Return a LayoutInflater instance that can be used to inflate  XML view layout
 * resources for use in this Window.
 *
 * @return LayoutInflater The shared LayoutInflater.
 */
 @Override
 public LayoutInflater getLayoutInflater() {
     return mLayoutInflater;
 }

(2)而参数mLayoutInflater在PhoneWindow的构造函数中是调用了from方法,其实就是使用了方式2.

public PhoneWindow(Context context) {
    super(context);
    mLayoutInflater = LayoutInflater.from(context);
}

(3)接着分析from方法。

/**
 * 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;
 }

该方法是调用了(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 即方式3. 

结论:三种创建LayoutInflater类对象的方式是一样的,都是调用了context.getSystemService()方法.

 
inflate方法
Inflate a new view hierarchy from the specified xml resource.
从指定的xml布局文件填充的新的视图层次结构。返回值是新的视图层次结构的根视图
有四个重载方法:
public View inflate (int resource, ViewGroup root)  
public View inflate (int resource, ViewGroup root, boolean attachToRoot) 
public View inflate (XmlPullParser parser, ViewGroup root)  
public View inflate (XmlPullParser parser, ViewGroup root, boolean attachToRoot)  

源码如下:

    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        <code>R.layout.main_page</code>)
     * @param root Optional view to be the parent of the generated hierarchy.
     * @return The root View of the inflated hierarchy. If root was supplied,
     *         this is the root View; otherwise it is the root of the inflated
     *         XML file.
     */
    public View inflate(int resource, ViewGroup root) {
        return inflate(resource, root, root != null);
    }

    /**
     * Inflate a new view hierarchy from the specified xml node. Throws
     * {@link InflateException} if there is an error. *
     * <p>
     * <em><strong>Important</strong></em>&nbsp;&nbsp;&nbsp;For performance
     * reasons, view inflation relies heavily on pre-processing of XML files
     * that is done at build time. Therefore, it is not currently possible to
     * use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
     * 
     * @param parser XML dom node containing the description of the view
     *        hierarchy.
     * @param root Optional view to be the parent of the generated hierarchy.
     * @return The root View of the inflated hierarchy. If root was supplied,
     *         this is the root View; otherwise it is the root of the inflated
     *         XML file.
     */
    public View inflate(XmlPullParser parser, ViewGroup root) {
        return inflate(parser, root, root != null);
    }

    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        <code>R.layout.main_page</code>)
     * @param root Optional view to be the parent of the generated hierarchy (if
     *        <em>attachToRoot</em> is true), or else simply an object that
     *        provides a set of LayoutParams values for root of the returned
     *        hierarchy (if <em>attachToRoot</em> is false.)
     * @param attachToRoot Whether the inflated hierarchy should be attached to
     *        the root parameter? If false, root is only used to create the
     *        correct subclass of LayoutParams for the root view in the XML.
     * @return The root View of the inflated hierarchy. If root was supplied and
     *         attachToRoot is true, this is root; otherwise it is the root of
     *         the inflated XML file.
     */
    public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        if (DEBUG) System.out.println("INFLATING from resource: " + resource);
        XmlResourceParser parser = getContext().getResources().getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }

    /**
     * Inflate a new view hierarchy from the specified XML node. Throws
     * {@link InflateException} if there is an error.
     * <p>
     * <em><strong>Important</strong></em>&nbsp;&nbsp;&nbsp;For performance
     * reasons, view inflation relies heavily on pre-processing of XML files
     * that is done at build time. Therefore, it is not currently possible to
     * use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
     * 
     * @param parser XML dom node containing the description of the view
     *        hierarchy.
     * @param root Optional view to be the parent of the generated hierarchy (if
     *        <em>attachToRoot</em> is true), or else simply an object that
     *        provides a set of LayoutParams values for root of the returned
     *        hierarchy (if <em>attachToRoot</em> is false.)
     * @param attachToRoot Whether the inflated hierarchy should be attached to
     *        the root parameter? If false, root is only used to create the
     *        correct subclass of LayoutParams for the root view in the XML.
     * @return The root View of the inflated hierarchy. If root was supplied and
     *         attachToRoot is true, this is root; otherwise it is the root of
     *         the inflated XML file.
     */
    public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            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;
            }

            return result;
        }
    }
LayoutInflater::inflater(...)

 

分析这四个方法:

1: public View inflate (int resource, ViewGroup root) 

resource:要加载的xml布局文件的ID
root:可选项。作为生成的视图层次结构的根视图。
return 填充的层次结构的根视图。如果参数root提供了,那么root就是根视图;否则填充的xml文件的根就是根视图。

 2:public View inflate ( XmlPullParser parser, ViewGroup root) 

parser:你需要解析xml的解析接口
root:可选项。作为生成的视图层次结构的根视图。
return 填充的层次结构的根视图。如果参数root提供了,那么root就是根视图;否则填充的xml文件的根就是根视图。

 3:public View inflate (int resource, ViewGroup root, boolean attachToRoot) 

resource:View的layout的ID
root:可选项。作为生成的视图层次结构的根视图。
attachToRoot:是否把选取的视图加入到root中。false 的意思就是不添加到root中。
return 填充的层次结构的根视图。如果参数root提供了,那么root就是根视图;否则填充的xml文件的根就是根视图。

 4:public View inflate ( XmlPullParser parser, ViewGroup root, boolean attachToRoot) 

parser:你需要解析View的xml的解析接口
root:可选项。作为生成的视图层次结构的根视图。
attachToRoot:是否把选取的视图加入到root中。false 的意思就是不添加到root中。
return 填充的层次结构的根视图。如果参数root提供了,那么root就是根视图;否则填充的xml文件的根就是根视图。

 

 写好的用例,可以用 hierarchy Viewer工具查看视图间的关系。