Activity setContentView流程

分析setContentView流程

frameworks/base/core/java/android/app/Activity.java路径下找到入口

public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        initActionBar();
    }

Activity又调用了mWindow中的setContentView

public Window getWindow() {
        return mWindow;
    }

看看mWindow是什么东西,attach方法中找到了mWindow的初始化

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config) {
       //...        
        mWindow = PolicyManager.makeNewWindow(this);
       //...
    }

frameworks/base/core/java/com/android/internal/policy/PolicyManager.java
跟着来到PolicyManager这个类中

public final class PolicyManager {
    //需要反射创建出来的对象
    private static final String POLICY_IMPL_CLASS_NAME =
        "com.android.internal.policy.impl.Policy";

    private static final IPolicy sPolicy;

    static {
       //...
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
            sPolicy = (IPolicy)policyClass.newInstance();
     //...
    }
    //...
    //我们的mWindow对象又是调用了sPolicy.makeNewWindow(context),所以继续跟
    public static Window makeNewWindow(Context context) {
        return sPolicy.makeNewWindow(context);
    }
//...
}

通过上面的代码能知道sPolicy.makeNewWindow(context)这个接口调用的方法实现类是
com.android.internal.policy.impl.Policy,我们去找。
frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java

public class Policy implements IPolicy {
   //...
        //终于知道了 mWindow 的对象是PhoneWindow实现的.
       public Window makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }

   //...
   }

好,到了这里终于知道Activity中的getWindow()对象就是PhoneWindow,那么继续去查找PhoneWindow中的setContentView

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    private LayoutInflater mLayoutInflater;

    //...
    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        //我们设置的activity_main.xml布局传到了这里,继续跟过去看看
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }       
    //...

}

到了这里知道我们平时设置的activity_main.xml被传入了 mLayoutInflater.inflate(layoutResID, mContentParent);方法中,路径是:
frameworks/base/core/java/android/view/LayoutInflater.java

public abstract class LayoutInflater {
//...
    //调用了下面的方法
    public View inflate(int resource, ViewGroup root) {
        return inflate(resource, root, root != null);
    }

//...
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        if (DEBUG) System.out.println("INFLATING from resource: " + resource);
        //获取xml解析器
        XmlResourceParser parser = getContext().getResources().getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
    //...
}

通过上面代码找到了Xml的解析器是 .getLayout(resource); 返回的,来看看代码

frameworks/base/core/java/android/content/res/Resources.java

public class Resources {
//...
final AssetManager mAssets;
//...
public XmlResourceParser getLayout(int id) throws NotFoundException {
        return loadXmlResourceParser(id, "layout");
    }
    //...
    //我们的activity_main.xml传到了这里
    XmlResourceParser loadXmlResourceParser(int id, String type)
            throws NotFoundException {
        synchronized (mTmpValue) {
            TypedValue value = mTmpValue;
            getValue(id, value, true);
            if (value.type == TypedValue.TYPE_STRING) {
                return loadXmlResourceParser(value.string.toString(), id,
                        value.assetCookie, type);
            }
   //...
        }
    }

    //...
    //activity_main.xml又传到了getValue当中
    public void getValue(int id, TypedValue outValue, boolean resolveRefs)
            throws NotFoundException {
         //AssetManager 对象中的 getResourceValue
        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
        if (found) {
            return;
        }
        throw new NotFoundException("Resource ID #0x"
                                    + Integer.toHexString(id));
    }
    //...
 }

frameworks/base/core/java/android/content/res/AssetManager.java
AssetManager 里的native方法不知道怎么调用的,没找到动态库加载,记录一下。

public final class AssetManager {
    //...
    /*package*/ final boolean getResourceValue(int ident,
                                               int density,
                                               TypedValue outValue,
                                               boolean resolveRefs)
    {
        //这是一个本地方法,去获取资源的block,其实是以个index
        int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
        if (block >= 0) {
            if (outValue.type != TypedValue.TYPE_STRING) {
                return true;
            }
            //给TyepValue 根据id获取string
            outValue.string = mStringBlocks[block].get(outValue.data);
            return true;
        }
        return false;
    }
    //...
}

回到frameworks/base/core/java/android/view/LayoutInflater.java
中去查看return inflate(parser, root, attachToRoot);这个方法。

public abstract class LayoutInflater {

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();
        }
    }

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(" can be used only with a valid "
                                + "ViewGroup root and attachToRoot=true");
                    }
                        //解析xml生成View的主要代码
                    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;
        }
    }
    }

    //...
    /**
     * Recursive method used to descend down the xml hierarchy and instantiate
     * views, instantiate their children, and then call onFinishInflate().
     */
    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)) {//这里是熟悉的include布局解析
                if (parser.getDepth() == 0) {
                    throw new InflateException(" cannot be the root element");
                }
                //跟着进入这个解析include布局方法
                parseInclude(parser, parent, attrs);
            } else if (TAG_MERGE.equals(name)) {
                throw new InflateException(" 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 {
            //上面一些特殊的布局解析完了以后,就到了这里
            //通过反射来创建我们的View
                final View view = createViewFromTag(parent, name, attrs);
                //获取这个view的父容器
                final ViewGroup viewGroup = (ViewGroup) parent;
                //生成这个ViewGroup 的属性
                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
                //递归创建整个Xml 里的控件
                rInflate(parser, view, attrs, true);
                //view添加到当前父容器中
                viewGroup.addView(view, params);
            }
        }

        if (finishInflate) parent.onFinishInflate();
    }
    //....
    private void parseInclude(XmlPullParser parser, View parent, AttributeSet attrs)
            throws XmlPullParserException, IOException {

        int type;
        //父View必须是ViewGroup的子类
        if (parent instanceof ViewGroup) {
            final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
            //获取include中layout的属性值,如果属性值是0 就进一步判断 value值是不是null的,null就抛异常
            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: ");
                } else {
                    throw new InflateException("You must specifiy a valid layout "
                            + "reference. The layout ID " + value + " is not valid.");
                }
            } else {
                //如果include的layout布局存在,就获取它的xml解析器
                final XmlResourceParser childParser =
                        getContext().getResources().getLayout(layout);

                try {
                     // 获取include标签中设置的属性
                    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();
                    //判断是否是merge标签
                    if (TAG_MERGE.equals(childName)) {
                        // Inflate all children.
                        rInflate(childParser, parent, childAttrs, false);
                    } else {
                        //这里的view就是创建了include进来的viewgroup子类根控件
                        final View view = createViewFromTag(parent, childName, childAttrs);
                        //这个是include layout的父容器
                        final ViewGroup group = (ViewGroup) parent;

                        ViewGroup.LayoutParams params = null;
                        try {// 获取include layout的父容器的属性
                            params = group.generateLayoutParams(attrs);
                        } catch (RuntimeException e) {
                            params = group.generateLayoutParams(childAttrs);
                        } finally {
                            if (params != null) {
                                //我们的include layout设置上属性
                                view.setLayoutParams(params);
                            }
                        }

                        //递归创建view,直到整个view树创建完成
                        // Inflate all children.
                        rInflate(childParser, view, childAttrs, true);

                        // Attempt to override the included layout's android:id with the
                        // one set on the  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();
                        //改变include layout的布局id,因为用include标签的时候都会带id,父容器会用这个id初始化
                        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;
                        }
                        //最后把include layout添加到它的父容器中。
                        group.addView(view);
                    }
                } finally {
                    childParser.close();
                }
            }
        } else {
            throw new InflateException(" 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
        }
    }
    //....

到这里就知道整个xml里面的控件是怎么通过解析后拿到name以后进行反射出来了。

你可能感兴趣的:(android源码分)