Android布局加载流程源码分析

本文深入探讨Android应用布局加载流程,从Activity的创建到PhoneWindow和DecorView的诞生,详细分析了布局如何加载到DecorView中,包括系统默认布局和自定义布局的挂载过程。

一.首先看布局层次

看这么几张图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

我们会发现DecorView里面包裹的内容可能会随着不同的情况而变化,但是在Decor之前的层次关系都是固定的。即Activity包裹PhoneWindow,PhoneWindow包裹DecorView。接下来我们首先看一下三者分别是如何创建的。

二.Activity是如何创建的

首先看到入口类ActivityThreadperformLaunchActivity方法:

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   
         
		...
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
   
   
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
   
   
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
   
   
            ...
        }

有句特别关键的代码,即

activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

所以activityInstrumentation类的newActivity方法创建的,追踪过去,源码如下

public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
   
   
        String pkg = intent != null && intent.getComponent() != null
                ? intent.getComponent().getPackageName() : null;
        return getFactory(pkg).instantiateActivity(cl, className, intent);
    }

追踪源码,可知getFactory方法返回一个AppComponentFactory对象,然后调用AppComponentFactoryinstantiateActivity方法,继续追踪

public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
   
   
        return (Activity) cl.loadClass(className).newInstance();
    }

到这里就结束了,我们可以发现Activity是通过反射创建的。
复习反射

三.PhoneWindow的创建

我们还是回到ActivityThreadperformLaunchActivity方法,在刚刚展示的那一段的下面有如下部分代码

		Window window = null;
        if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
   
   
            window = r.mPendingRemoveWindow;
            r.mPendingRemoveWindow = null;
            r.mPendingRemoveWindowManager = null;
        }

        // Activity resources must be initialized with the same loaders as the
        // application context.
        appContext.getResources().addLoaders(
                app.getResources().getLoaders().toArray(new ResourcesLoader[0]));

        appContext.setOuterContext(activity);
        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, r.configCallback,
                r.assistToken);

activity.attach这个方法中,传入了一个Window对象,追踪这个attach方法,里面有一句关键代码

mWindow = new PhoneWindow(this, window, activityConfigCallback);

此时就创建了PhoneWindow。所以我们可以知道,在Activity创建完之后,会为当前的Activity创建一个PhoneWindow对象。

三.DecorView的创建

DecorView的创建就不是performLaunchActivity方法里面了,这次我们从ActivitysetContentView的源码开始分析。下面的ActivitysetContentView方法的内容。

public void setContentView(@LayoutRes int layoutResID) {
   
   
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

我们发现,ActivitysetContentView实际是调用了PhoneWindowsetContentView方法,跟踪源码。我们会首先进入Window抽象类,然后我们找其子类PhoneWindow,在里面找到setContentView方法

public void setContentView(int layoutResID) {
   
   
        if (mContentParent == null) {
   
   
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
   
   
            mContentParent.removeAllViews();
        }
		...

mContentParentnull时,会调用installDecor方法,追踪进入

private void installDecor() {
   
   
        mForceDecorInstall = false;
        if (mDecor == null) {
   
   
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
   
   
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
   
   
            mDecor.setWindow(this);
        }
        ...

它调用了generateDecor方法,追踪进入

protected DecorView generateDecor(int featureId) {
   
   
        // System process doesn't have application context and in that case we need to directly use
        // the context we have. Otherwise we want the application context, 
评论 17
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值