转载自:http://blog.csdn.net/u013356254/article/details/55052363

android交流:364595326

<h3>源码分析之LayoutInflater</h3>

<h4>简介</h4>

<ul>

<li>

基于5.0的framework源码进行分析,通过这篇文章我们能了解:

<ul>

<li>LayoutInflater的系统级服务的注册过程</li>

<li>inflate填充的过程</li>

<li>ViewStub,merge,include的加载过程</li>

</ul>

</li>

</ul>

<h4>LayoutInflater系统服务的注册过程</h4>

<ul>

<li>

<p>我们经常调用</p>

<pre><code>context.getSystemService(Context.LAYOUT_INFLATE_SERVICE)

</code></pre>


<p>获得<strong>LayoutInflater</strong>对象。那么这个对象是什么时候注册到Context中的呢?这个对象的具体实现类是谁?</p>

<ul>

<li>LayoutInflater这个服务,是在创建Activity的时候,作为<strong>baseContext</strong>传递给Activity的。接下来我们看源码过程。</li>

<li>

<p>我们知道<strong>Activity</strong>的创建过程是在<strong>ApplicationThread<strong>的</strong>performLaunchActivity</strong>方法中。那么接下来我们分析这个方法</p>

<pre><code> private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    /*/

    Activity activity = null;

    try{

        // 通过Instrumentation类创建Activity

         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

activity = mInstrumentation.newActivity(

        cl, component.getClassName(), r.intent);


        }catch(Exeception e){}

    /*/

    // 创建Context过程,也就是baseContext

     Context appContext = createBaseContextForActivity(r, activity);

    // 关联activity和baseContext

    activity.attach(appContext, this, getInstrumentation(), r.token,

            r.ident, app, r.intent, r.activityInfo, title, r.parent,

            r.embeddedID, r.lastNonConfigurationInstances, config,

            r.referrer, r.voiceInteractor, window);


 }  

</code></pre>


</li>

<li>

<p>那么接下来我们只要分析</p>

<pre><code> Context appContext = createBaseContextForActivity(r, activity);

</code></pre>


<p>这个方法即可,源码继续</p>

<pre><code> private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {

    // 通过调用ContextImpl的静态方法创建baseContext对象

    ContextImpl appContext = ContextImpl.createActivityContext(

            this, r.packageInfo, r.token, displayId, r.overrideConfig);

    appContext.setOuterContext(activity);

    return baseContext;

}

</code></pre>


</li>

<li>

<p>接下来分析</p>

<pre><code>ContextImpl.createActivityContext(

                this, r.packageInfo, r.token, displayId, r.overrideConfig);

        appContext.setOuterContext(activity);

</code></pre>


<p>接下来我们分析下ContextImpl这个类,发现其有一个成员变量</p>

<pre><code>    // 在这里注册系统级别的服务

// The system service cache for the system services that are cached per-ContextImpl.

final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();

</code></pre>


</li>

</ul>

<p>SystemServiceRegistry类有个静态代码块,完成了常用服务的注册,代码如下 </p>

<pre><code>static{

    // 注册LayoutLAYOUT_INFLATER_SERVICE系统服务,具体实现类是PhoneLayoutInflater

     registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,

            new CachedServiceFetcher&lt;LayoutInflater&gt;() {

        @Override

        public LayoutInflater createService(ContextImpl ctx) {

            return new PhoneLayoutInflater(ctx.getOuterContext());

        }});

    // 注册AM 

     registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,

        new CachedServiceFetcher&lt;ActivityManager&gt;() {

    @Override

    public ActivityManager createService(ContextImpl ctx) {

        return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());

    }});

    // 注册WM

     registerService(Context.WINDOW_SERVICE, WindowManager.class,

        new CachedServiceFetcher&lt;WindowManager&gt;() {

    @Override

    public WindowManager createService(ContextImpl ctx) {

        return new WindowManagerImpl(ctx);

    }});

    // 等等

      }

</code></pre>


</li>

<li>

<p>接下来我们看inflate过程,下面是整个inflate过程</p>

<pre><code>public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {

synchronized (mConstructorArgs) {

    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");


    final Context inflaterContext = mContext;

    final AttributeSet attrs = Xml.asAttributeSet(parser);

    Context lastContext = (Context) mConstructorArgs[0];

    mConstructorArgs[0] = inflaterContext;

    View result = root;


    try {

        // 循环找到第一个view节点,

        int type;

        while ((type = parser.next()) != XmlPullParser.START_TAG &amp;&amp;

                type != XmlPullParser.END_DOCUMENT) {

            // Empty

        }

        // 这里判断是否是第一个view节点

        if (type != XmlPullParser.START_TAG) {

            throw new InflateException(parser.getPositionDescription()

                    + ": No start tag found!");

        }


        final String name = parser.getName();

       // 解析merge标签

        if (TAG_MERGE.equals(name)) {

            if (root == null || !attachToRoot) {

                throw new InflateException("&lt;merge /&gt; can be used only with a valid "

                        + "ViewGroup root and attachToRoot=true");

            }

            // 通过rInflate方法将merge标签下的孩子直接合并到root上,这样减少一层布局,达到减少viewTree的目的

            rInflate(parser, root, inflaterContext, attrs, false);

        } else {

            // 调用反射创建view对象

            final View temp = createViewFromTag(root, name, inflaterContext, attrs);


            ViewGroup.LayoutParams params = null;


            if (root != null) {

                // Create layout params that match root, if supplied

                params = root.generateLayoutParams(attrs);

                if (!attachToRoot) {

                    // 如果view的父容器不为null,并且attachToRoot未true得话,这里只是让刚刚通过反射创建的view使用root(父容器的布局参数)

                    temp.setLayoutParams(params);

                }

            }



            // 通过深度遍历temp下的节点,之后将节点依次添加到刚刚通过反射创建的temp对象上,因为采用的是深度优先遍历算法,因此viewTree的层级很深的话,会影响遍历的性能

            rInflateChildren(parser, temp, attrs, true);

           // 判断刚刚创建的temp对象是否添加到父节点上.

            // 满足两个条件1 父节点(root)不为null,2 attachToRoot=true

            if (root != null &amp;&amp; attachToRoot) {

                root.addView(temp, params);

            }


            // 设置result

            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) {


    } finally {

        // Don't retain static reference on context.

        mConstructorArgs[0] = lastContext;

        mConstructorArgs[1] = null;


        Trace.traceEnd(Trace.TRACE_TAG_VIEW);

    }

    // 返回


    return result;

}

</code></pre>


<p>}</p>

<ul>

<li>通过上面分析,我们对inflate的整体过程有了一个了解,也见到了merge标签(经常作为布局文件根节点,来达到减少viewTree的层次)</li>

<li>接下来,我们分析4个方法</li>

<li>rInflate(parser, root, inflaterContext, attrs, false);,其实不管是根节点为merge还是普通的view(最终都会用这个方法),深度遍历添加view</li>

<li>

<p>下面是代码</p>

<pre><code>    // 深度遍历添加孩子

 void rInflate(XmlPullParser parser, View parent, Context context,

            AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {


    final int depth = parser.getDepth();

    int type;


    while (((type = parser.next()) != XmlPullParser.END_TAG ||

            parser.getDepth() &gt; depth) &amp;&amp; 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)) {

        // 如果我们调用了View.setTag(),将会执行下面代码

            parseViewTag(parser, parent, attrs);

        // include不能作为根节点

        } else if (TAG_INCLUDE.equals(name)) {

            if (parser.getDepth() == 0) {

                throw new InflateException("&lt;include /&gt; cannot be the root element");

            }

            // 这里解析include标签代码

            parseInclude(parser, context, parent, attrs);

        } else if (TAG_MERGE.equals(name)) {

            // merge一定是根节点

            throw new InflateException("&lt;merge /&gt; must be the root element");

        } else {

            final View view = createViewFromTag(parent, name, context, attrs);

            final ViewGroup viewGroup = (ViewGroup) parent;

            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);

            // 递归,因为rInflateChildren最终还会调用rInflate(parser, parent, parent.getContext(), attrs, finishInflate);方法

            rInflateChildren(parser, view, attrs, true);

            viewGroup.addView(view, params);

        }

    }


    if (finishInflate) {

        // viewTree填充完毕,回调自定义view经常使用的onFinishInflate方法

        parent.onFinishInflate();

    }

}

</code></pre>


</li>

<li>

<p>rInflateChildren(parser, view, attrs, true);方法</p>

<pre><code>    // 直接调用rInflate()实现ViewTree

 final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,

    boolean finishInflate) throws XmlPullParserException, IOException {

rInflate(parser, parent, parent.getContext(), attrs, finishInflate);

</code></pre>


<p>}</p>

</li>

<li>

<p>createViewFromTag(root, name, inflaterContext, attrs);方法,这个方法其实处理了自定义view和系统view的创建。最终调用了下面方法</p>

<pre><code>     View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,

        boolean ignoreThemeAttr) {

    if (name.equals("view")) {

        name = attrs.getAttributeValue(null, "class");

    }


    // 设置view默认样式

    if (!ignoreThemeAttr) {

        final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);

        final int themeResId = ta.getResourceId(0, 0);

        if (themeResId != 0) {

            context = new ContextThemeWrapper(context, themeResId);

        }

        ta.recycle();

    }


    try {

        View view;

        if (view == null) {

            final Object lastContext = mConstructorArgs[0];

            mConstructorArgs[0] = context;

            try {//创建系统view的方法,因为系统view的标签不是完整类名,需要会在 onCreateView中完成拼接(拼接出系统view的完整类名)

                if (-1 == name.indexOf('.')) {

                    view = onCreateView(parent, name, attrs);

                } else {

                    //自定义view的创建

                    view = createView(name, null, attrs);

                }

            } finally {

                mConstructorArgs[0] = lastContext;

            }

        }


        return view;

    } catch (InflateException e) {

        throw e;


    } catch (ClassNotFoundException e) {

        final InflateException ie = new InflateException(attrs.getPositionDescription()

                + ": Error inflating class " + name, e);

        ie.setStackTrace(EMPTY_STACK_TRACE);

        throw ie;


    } catch (Exception e) {

        final InflateException ie = new InflateException(attrs.getPositionDescription()

                + ": Error inflating class " + name, e);

        ie.setStackTrace(EMPTY_STACK_TRACE);

        throw ie;

    }

}

</code></pre>


</li>

<li>

<p>接下来我们分析 createView(String name, String prefix, AttributeSet attrs)方法,系统view的创建,最终也会调用createView方法。只不过在前面拼接上了系统view的包名。</p>

<pre><code>     public final View createView(String name, String prefix, AttributeSet attrs)

        throws ClassNotFoundException, InflateException {

    // 获取view的构造方法

    Constructor&lt;? extends View&gt; constructor = sConstructorMap.get(name);

    // 验证

    if (constructor != null &amp;&amp; !verifyClassLoader(constructor)) {

        constructor = null;

        sConstructorMap.remove(name);

    }

    Class&lt;? extends View&gt; clazz = null;


    try {

        if (constructor == null) {


            clazz = mContext.getClassLoader().loadClass(

                    prefix != null ? (prefix + name) : name).asSubclass(View.class);


            if (mFilter != null &amp;&amp; clazz != null) {

                boolean allowed = mFilter.onLoadClass(clazz);

                if (!allowed) {

                    failNotAllowed(name, prefix, attrs);

                }

            }

            constructor = clazz.getConstructor(mConstructorSignature);

            constructor.setAccessible(true);

            // 将view的构造方法缓存起来

            sConstructorMap.put(name, constructor);

        } else {

          /*/

        }


        Object[] args = mConstructorArgs;

        args[1] = attrs;

        // 反射创建view对象

        final View view = constructor.newInstance(args);

        // 对viewStub进行处理

        if (view instanceof ViewStub) {

            // 给ViewStub设置LayoutInfalter.什么时候inflate,什么时候viewStub的内容才显示,(比GONE性能好)

            final ViewStub viewStub = (ViewStub) view;

            viewStub.setLayoutInflater(cloneInContext((Context) args[0]));

        }

        return view;


    } catch (NoSuchMethodException e) {



    } catch (ClassCastException e) {


    } catch (ClassNotFoundException e) {


    } catch (Exception e) {


    } finally {


    }

}

</code></pre>


</li>

</ul>

</li>

</ul>

<h4>总结</h4>

<ul>

<li>系统服务的填充过程,是在ContextImpl中完成注册的</li>

<li>LayoutInflater的实现类是PhoneLayoutInflater</li>

<li>如果仅仅使用父容器的布局参数,可以使用inflater.inflate(layoutId,parent,false);</li>

<li>onFinishInflate()方法是在viewTree遍历完成之后,调用的</li>

<li>merge标签只能是根节点,include标签不能是根节点。</li>

<li>

布局优化

<ul>

<li>view的inflate的过程是深度遍历,因此应该尽量减少viewTree的层次,可以考虑使用merge标签</li>

<li>如果我们不知道view什么时候填充的时候,可以使用ViewStub标签,什么时候用什么时候填充</li>

<li>include是提升复用的</li></ul></li></ul>