Activity.setContentView方法-浅析

为什么((ViewGroup)getWindow.getDecorView().findViewById(android.R.id.content)).getChildAt(0),能够获取我们通过setContentView设置的layout布局对象?

这主要是因为layout布局就放在android.R.id.content对应的控件中。大概流图如下:
这里写图片描述
执行顺序为1, 2, 4, 5, 3,接下来通过代码片段来说明。

本文基于API19的源代码讲解。

我们会在Activity中调用setContentView(R.layout.main)来设置布局,以下为主要代码片段

1.1 Activity.setContentView

/**
 * Set the activity content to an explicit view.
 * 将显视的view设置到activity的content中  
 * This view is placed directly into the activity's view hierarchy.
 * view被直接放置到activity的view层次结构中  
 * It can itself be a complex view hierarchy.
 * activity本身就是一个复杂的view层次结构
 */
public void setContentView(int layoutResID) {
    //调用了Window的setContentView,实际调用的是子类PhoneWindow的方法
    getWindow().setContentView(layoutResID);
    initActionBar();
}

Activity提供的方法注释

1.2 Window.setContentView

/**  
 * Convenience for 
 * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}  
 * set the screen content to an explicit view.  This view is placed 
 * directly into the screen's view hierarchy.  It can itself be a complex 
 * view hierarhcy. 
 */
public abstract void setContentView(int layoutResID);

1.3 PhoneWindow.setContentView

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {

        installDecor();
    } else {
        mContentParent.removeAllViews();
    }
    mLayoutInflater.inflate(layoutResID, mContentParent);
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}
1.3.1 PhoneWindow.setContentView->installDecor
private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();
        ...
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
        ...
    }
}
1.3.1.1 PhoneWindow.setContentView->installDecor->generateDecor

实例化DecorView对象

protected DecorView generateDecor() {
    return new DecorView(getContext(), -1);
}
1.3.1.2 PhoneWindow.setContentView->installDecor->generateLayout

向DecorView中添加系统预设的layout,并返回R.id.content对应FrameLayout控件

protected ViewGroup generateLayout(DecorView decor) {
    ...
    if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
        //系统提供的布局文件
        layoutResource = com.android.internal.R.layout.screen_action_bar;
    } else {
        //系统提供的布局文件
        layoutResource = com.android.internal.R.layout.screen_title;
    }
    ...
    mDecor.startChanging();
    //实例化布局screen_action_bar(debug时走的这条路),并将其添加到DecorView中
    View in = mLayoutInflater.inflate(layoutResource, null);
    //我们在activity中设置的布局文件,最后就会添加到这个布局中
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    //找到R.id.content控件FrameLayout
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    if (contentParent == null) {
        throw new RuntimeException("Window couldn't find content container view");
    }
    ...
    return contentParent;
}
1.3.2 PhoneWindow.setContentView->LayoutInflater.inflate
/**  
 * Inflate a new view hierarchy from the specified xml resource. Throws 
 * {@link InflateException} if there is an error.
 * 将xml布局文件转化为一个view层次结构
 * @param resource ID for an XML layout resource to load (e.g.,  
 * <code>R.layout.main_page</code>)  
 * 通过setContentView设置的布局资源
 * @param root Optional view to be the parent of the generated hierarchy. 
 * root为DecorView中,id是R.id.content的FrameLayout控件 
 * @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. 
 *         提供root,则转换出来的view有root相关层次结构;没有提供则转换出来的只有xml中的view层次结构
 */
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);
    XmlResourceParser parser = getContext().getResources().getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
    ...
    View result = root;
    ...
    // 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);
    }
    ...
    //以上步骤将resource中的view全部添加到root中
    return result;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值