从源码看LayoutInflater创建View的过程

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(); 
       final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
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 {
                // 查找根节点
               ...
                final String name = parser.getName();
                if (TAG_MERGE.equals(name)) {
                    rInflate(parser, root, attrs, false, false);
                } else {
                    //创建根View
                    final View temp = createViewFromTag(root, name, attrs, false);
                    ViewGroup.LayoutParams params = null;
                    if (root != null) {
                        params = root.generateLayoutParams(attrs);
                        if (!attachToRoot) {
                            temp.setLayoutParams(params);
                        }
                    }
                    //递归创建子View
                    rInflate(parser, temp, attrs, true, true);
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }
                    if (root == null || !attachToRoot) {
                        result = temp;
                    }
                }
            return result;
        }
    }

过程大致如下:

  1. 首先根据layout的资源id,创建对应的XmlResouceParser
  2. XMLResourceParser找到根标签。
  3. 如果根标签不是merge的话,则通过createViewFromTag创建相应的View,然后递归的创建子View
  4. 如果设置了attachToRoot,则将将根View添加到rootView中,然后返回rootView;否则返回根view。

xml中根节点设置的layout_width和Layout_height有时不起作用,关键要看infalte时,是否传了rootView,并设置attachToRoot为true。

View createViewFromTag(View parent, String name, AttributeSet attrs, boolean inheritContext) {
        if (name.equals("view")) {
            name = attrs.getAttributeValue(null, "class");
        }
        Context viewContext;
        if (parent != null && inheritContext) {
            viewContext = parent.getContext();
        } else {
            viewContext = mContext;
        }

        // 应用主题
        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();
        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;
                }
            }
            return view;

        } 

依次分别由mFactory2、mFactory、mPrivateFactory创建View,如果都没有创建,则由LayoutInflater自己创建。
下面看看LayoutInflater是如何创建的

 public final View createView(String name, String prefix, AttributeSet attrs)
            throws ClassNotFoundException, InflateException {
        Constructor constructor = sConstructorMap.get(name);
        Class clazz = null;

        try {
            if (constructor == null) {
                clazz = mContext.getClassLoader().loadClass(
                        prefix != null ? (prefix + name) : name).asSubclass(View.class);
                constructor = clazz.getConstructor(mConstructorSignature);
                sConstructorMap.put(name, constructor);
            } else {
            Object[] args = mConstructorArgs;
            args[1] = attrs;
            constructor.setAccessible(true);
            final View view = constructor.newInstance(args);
            return view;
        } 

LayoutInflater内有View构造函数的缓存,当存在该View的构造函数时,直接拿来创建实例,否则通过context.getClassLoader,由classLoader去loadClass,然后获得该类的构造函数,并存入缓存,然后调用构造函数创建View。

那mFactory2、mFactory和mPrivateFactory是用来干什么的呢?它们之间是什么关系?这三个变量是何时被赋值的?
第一个问题的答案是,可以对LayoutInflater从xml中创建View的过程进行扩展。
对于第二个问题,来看一下Factory和Factory2的定义

public interface Factory {
       public View onCreateView(String name, Context context, AttributeSet attrs);
}
public interface Factory2 extends Factory {
        public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
}

Factory2继承于Factory,增加了一个接口。其中mFractory是Factory类型的,mFactory2和mPrivateFactory是Factory2类型的。你要是去看Android源码修改日志的话,可以看到最初的时候只有mFactory,后来为了支持Fragment才增加了mFactory2,后来又有了mPrivateFactory。
之所以还留着Factory,是为了向下兼容。
第三个问题,三个Factory是何时被赋值的?
如果看一下Activity的定义的话,你会发现Activity实现了Factory2接口。并且在attach方法中,将自己设置为LayoutInflater的privateFactory。

mWindow.getLayoutInflater().setPrivateFactory(this);

这是你就会明白了,当我们使用LayoutInflater来inflate View的时候,首先会走到Activity的onCreateView中,如果返回了null,才会由LayoutInflater继续创建View。我们来看一下Activity的onCreateView是如何实现的

public View onCreateView(String name, Context context, AttributeSet attrs) {
       return null;
}

public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
       if (!"fragment".equals(name)) {
           return onCreateView(name, context, attrs);
       }
       return mFragments.onCreateView(parent, name, context, attrs);
}

如果是fragment的话,则由mFragments去创建,否则返回null。
而mFragments的类型是FragmentManagerImpl。
这样就说的通了,以前的时候Android是不支持Fragment的,View都由LayoutInflater直接创建,后来为了支持Fragment,让Activity来实现Factory2,从而拦截对Fragment的创建,后来又把Fragment相关的代码移到了FragmentManager中。
这时候你可以会说,我用的不是Activity,而是FragmentActivity。

从源码看LayoutInflater创建View的过程_第1张图片

在BaseFragmentActivityDonut代码中

protected void onCreate(Bundle savedInstanceState) {
        if (Build.VERSION.SDK_INT < 11 && getLayoutInflater().getFactory() == null) {
            getLayoutInflater().setFactory(this);
        }
        super.onCreate(savedInstanceState);
    }

如果系统Build版本小于11,LayoutInflater的mFactory被设置为Activity,而11之后,则是mPrivateFactory被设置为Activity。

你可能感兴趣的:(从源码看LayoutInflater创建View的过程)