Activity是如何加载布局文件的?

概要

一个activity它其实包含着一个window,所有的ui其实都是显示在这个window上的,Window类是一个抽象类,真正的实现类为PhoneWindow,在activity中调用的setContentView方法实际上就是调用PhoneWindow的setContentView方法。

PhoneWindow中包含一个成员变量DecorView和mContentParent。

DecorView它其实就是一个window的顶级view,通过代码可以知道DecorView它就是一个FrameLayout,一般情况下DecorView加载一个xml布局文件,包含TitleBar(可以理解为actionbar部分)和ContentView(实体内容部分,为FrameLayout, id为content)。

mContentParent它其实就是DecorView的ContentView部分,当我们设置activity没有actionbar的时候,mContentParent等同于DecorView,PhoneWindow中调用的setContentView方法其实就是将外部传递过来的布局文件加载到mContentParent中。

这里写图片描述

下面我们看看具体的代码实现细节。

1、OurActivity

在我们的Activity中,我们通常是在onCreate函数中掉用setContentView方法来加载布局文件,具体如下:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_eight_chapter);

    initView();
}

点击进去可以看到掉用的是Activity中的setContentView方法。

2、Activity

/**
 * Set the activity content from a layout resource.  The resource will be
 * inflated, adding all top-level views to the activity.
 *
 * @param layoutResID Resource ID to be inflated.
 *
 * @see #setContentView(android.view.View)
 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
 */
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

通过注释知道这个方法是将资源布局设置为activity的内容,资源将被添加到Activity最顶层的View上。

Activity中setContentView方法中通过掉用getWindow().setContentView(layoutResID)来加载布局资源;

getWindow()返回的是mWindow,接下来看看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, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

    // 此处进行初始化
    mWindow = new PhoneWindow(this, window);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    mUiThread = Thread.currentThread();

    mMainThread = aThread;
    mInstrumentation = instr;
    mToken = token;
    mIdent = ident;
    mApplication = application;
    mIntent = intent;
    mReferrer = referrer;
    mComponent = intent.getComponent();
    mActivityInfo = info;
    mTitle = title;
    mParent = parent;
    mEmbeddedID = id;
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    if (voiceInteractor != null) {
        if (lastNonConfigurationInstances != null) {
            mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
        } else {
            mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                    Looper.myLooper());
        }
    }

    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;
}

可以看到mWindow对象,这个对象是window 接口的实现类 PhoneWindow 的实例。

下面我们看看PhoneWindow方法中的SetContentView方法代码是如何实现的。

3、PhoneWindow

@Override
public void setContentView(int layoutResID) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}

通过代码,我们先看看mContentParent是什么类型,installDecor方法有做了哪些是,其实猜测也可以知道installDecor应该是对mContentParent做了初始化的操作。

// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;

private void installDecor() {  
    if (mDecor == null) {  
        mDecor = generateDecor();  
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);  
        mDecor.setIsRootNamespace(true);  
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {  
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);  
        }  
    }  
    if (mContentParent == null) {  
        mContentParent = generateLayout(mDecor);  

        // Set up decor part of UI to ignore fitsSystemWindows if appropriate.  
    //.....  
    //...... 省略若干代码  
    }  
}  

通过注释可以知道mDecor是window的最顶层view,mContentParent可以是mDecor也可以是mDecor的一个孩子。

DecorView是什么呢?

public class DecorView extends FrameLayout{},可以知道DecorView其实就是一个FrameLayout。

通过mLayoutInflater.inflate(layoutResID, mContentParent);我们就清楚了在Activity中设置的layoutid 在这里加载到了mContentParent 上面。也就是所有的所有的View 对象都是加载到了mContentParent对象上面,而我们前面知道mContentParent是根据DecorView而来的,这样我们就清楚了Activity与Window以及View的关系了。

总结

1、Activity就像是一扇贴着窗花的窗口,Window就想上窗口上面的玻璃,而View对象就像一个个贴在玻璃上的窗花。

2、Activity会调用PhoneWindow的setContentView()将layout布局添加到DecorView上,而此时的DecorView就是那个最底层的View。然后通过LayoutInflater.infalte()方法加载布局生成View对象并通过addView()方法添加到Window上,(一层一层的叠加到Window上)所以,Activity其实不是显示视图,Window才是真正的显示视图。

参考网址

http://blog.csdn.net/qian520ao/article/details/78555397

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值