千家信息网

怎么浅析Activity的渲染过程

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,今天就跟大家聊聊有关怎么浅析Activity的渲染过程,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。####以下代码基于API251.Acti
千家信息网最后更新 2026年11月03日怎么浅析Activity的渲染过程

今天就跟大家聊聊有关怎么浅析Activity的渲染过程,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

####以下代码基于API25

1.Activity是如何展现在我们眼前的?

我大概知道UI方面是和Window相关的,而activity的attach方法会传入一个window对象,所以就从activity的attach方法入手:

    • attach方法里会创建一个PhoneWindow

    • activity在执行onCreate方法的时候都会执行一个方法performCreateCommon

    • 点击setEnterActivityOptions方法:

    注意window.getDecorView()这个方法



    /**
    * Retrieve the top-level window decor view (containing the standard
    * window frame/decorations and the client's content inside of that), which
    * can be added as a window to the window manager.
    *
    *

    Note that calling this function for the first time "locks in"
    * various window characteristics as described in
    * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.


    *
    * @return Returns the top-level window decor view.
    */
    public abstract View getDecorView();


    官方的解释是说这个方法是获取了顶层window的decorview。

    这里的window很明显是PhoneWindow,看它对getDecorView的实现。

mDecor其实在PhoneWindow的构造方法里就已经生成了

preservedWindow向上追溯其来源:

从onCreate里其实根本就找不到activity显示相关的源码,于是只能看看其他人怎么分析的。

https://www.aliyun.com/jiaocheng/6995.html (道中重点)

https://www.cnblogs.com/snow-flower/p/6111599.html

https://blog.csdn.net/monkey646812329/article/details/52885835

if (r.window == null && !a.mFinished && willBeVisible) {    r.window = r.activity.getWindow();    View decor = r.window.getDecorView();    decor.setVisibility(View.INVISIBLE);    ViewManager wm = a.getWindowManager();    WindowManager.LayoutParams l = r.window.getAttributes();    a.mDecor = decor;    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;    l.softInputMode |= forwardBit;    if (r.mPreserveWindow) {        a.mWindowAdded = true;        r.mPreserveWindow = false;        // Normally the ViewRoot sets up callbacks with the Activity        // in addView->ViewRootImpl#setView. If we are instead reusing        // the decor view we have to notify the view root that the        // callbacks may have changed.        ViewRootImpl impl = decor.getViewRootImpl();        if (impl != null) {            impl.notifyChildRebuilt();        }    }    if (a.mVisibleFromClient && !a.mWindowAdded) {        a.mWindowAdded = true;        wm.addView(decor, l);    }// If the window has already been added, but during resume// we started another activity, then don't yet make the// window visible.} else if (!willBeVisible) {    if (localLOGV) Slog.v(        TAG, "Launch " + r + " mStartedActivity set");    r.hideForNow = true;}

看上面的源码

得到PhoneWindow对象

   r.window = r.activity.getWindow();      View decor = r.window.getDecorView();

从PhoneWindow获取DecorView并赋值给activity

    a.mDecor = decor;

通过WindowManager添加decor

wm.addView(decor, l);

这样activity就展示在我们眼前了。关于WindowManager更加底层的源码后探讨。

2.Activity的setContentView方法

/** * 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();}/** * Set the activity content to an explicit view.  This view is placed * directly into the activity's view hierarchy.  It can itself be a complex * view hierarchy.  When calling this method, the layout parameters of the * specified view are ignored.  Both the width and the height of the view are * set by default to {@link ViewGroup.LayoutParams#MATCH_PARENT}. To use * your own layout parameters, invoke * {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)} * instead. * * @param view The desired content to display. * * @see #setContentView(int) * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) */public void setContentView(View view) {    getWindow().setContentView(view);    initWindowDecorActionBar();}/** * Set the activity content to an explicit view.  This view is placed * directly into the activity's view hierarchy.  It can itself be a complex * view hierarchy. * * @param view The desired content to display. * @param params Layout parameters for the view. * * @see #setContentView(android.view.View) * @see #setContentView(int) */public void setContentView(View view, ViewGroup.LayoutParams params) {    getWindow().setContentView(view, params);    initWindowDecorActionBar();}/** * Add an additional content view to the activity.  Added after any existing * ones in the activity -- existing views are NOT removed. * * @param view The desired content to display. * @param params Layout parameters for the view. */public void addContentView(View view, ViewGroup.LayoutParams params) {    getWindow().addContentView(view, params);    initWindowDecorActionBar();}

关于填充view,activity有4种方法。下面先讨论最常用的方法

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

第一步调用PhoneWindow的对应的方法(注意观察源码会发现,activity的绝大多数的方法都是在操作PhoneWindow)

第二步初始化ActionBar

先看看PhoneWindow的源码

@Overridepublic 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;}

最开始程序应该是走了installDecor方法

这个方法比较长,它负责的业务主要有以下几项。

  • 如果decor为null,创建PhoneWindow的decor,已经存在decor则与PhoneWindow绑定。

  • 如果mContentParent为null,通过decor创建mContentParent。

  • 转场动画的处理

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);    }    if (mContentParent == null) {        mContentParent = generateLayout(mDecor);        // Set up decor part of UI to ignore fitsSystemWindows if appropriate.        mDecor.makeOptionalFitsSystemWindows();        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(                R.id.decor_content_parent);        if (decorContentParent != null) {            mDecorContentParent = decorContentParent;            mDecorContentParent.setWindowCallback(getCallback());            if (mDecorContentParent.getTitle() == null) {                mDecorContentParent.setWindowTitle(mTitle);            }            final int localFeatures = getLocalFeatures();            for (int i = 0; i < FEATURE_MAX; i++) {                if ((localFeatures & (1 << i)) != 0) {                    mDecorContentParent.initFeature(i);                }            }            mDecorContentParent.setUiOptions(mUiOptions);            if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||                    (mIconRes != 0 && !mDecorContentParent.hasIcon())) {                mDecorContentParent.setIcon(mIconRes);            } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&                    mIconRes == 0 && !mDecorContentParent.hasIcon()) {                mDecorContentParent.setIcon(                        getContext().getPackageManager().getDefaultActivityIcon());                mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;            }            if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||                    (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {                mDecorContentParent.setLogo(mLogoRes);            }            // Invalidate if the panel menu hasn't been created before this.            // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu            // being called in the middle of onCreate or similar.            // A pending invalidation will typically be resolved before the posted message            // would run normally in order to satisfy instance state restoration.            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);            if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {                invalidatePanelMenu(FEATURE_ACTION_BAR);            }        } else {            mTitleView = (TextView) findViewById(R.id.title);            if (mTitleView != null) {                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {                    final View titleContainer = findViewById(R.id.title_container);                    if (titleContainer != null) {                        titleContainer.setVisibility(View.GONE);                    } else {                        mTitleView.setVisibility(View.GONE);                    }                    mContentParent.setForeground(null);                } else {                    mTitleView.setText(mTitle);                }            }        }        if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {            mDecor.setBackgroundFallback(mBackgroundFallbackResource);        }        // Only inflate or create a new TransitionManager if the caller hasn't        // already set a custom one.        if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {            if (mTransitionManager == null) {                final int transitionRes = getWindowStyle().getResourceId(                        R.styleable.Window_windowContentTransitionManager,                        0);                if (transitionRes != 0) {                    final TransitionInflater inflater = TransitionInflater.from(getContext());                    mTransitionManager = inflater.inflateTransitionManager(transitionRes,                            mContentParent);                } else {                    mTransitionManager = new TransitionManager();                }            }            mEnterTransition = getTransition(mEnterTransition, null,                    R.styleable.Window_windowEnterTransition);            mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,                    R.styleable.Window_windowReturnTransition);            mExitTransition = getTransition(mExitTransition, null,                    R.styleable.Window_windowExitTransition);            mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,                    R.styleable.Window_windowReenterTransition);            mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,                    R.styleable.Window_windowSharedElementEnterTransition);            mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,                    USE_DEFAULT_TRANSITION,                    R.styleable.Window_windowSharedElementReturnTransition);            mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,                    R.styleable.Window_windowSharedElementExitTransition);            mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,                    USE_DEFAULT_TRANSITION,                    R.styleable.Window_windowSharedElementReenterTransition);            if (mAllowEnterTransitionOverlap == null) {                mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(                        R.styleable.Window_windowAllowEnterTransitionOverlap, true);            }            if (mAllowReturnTransitionOverlap == null) {                mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(                        R.styleable.Window_windowAllowReturnTransitionOverlap, true);            }            if (mBackgroundFadeDurationMillis < 0) {                mBackgroundFadeDurationMillis = getWindowStyle().getInteger(                        R.styleable.Window_windowTransitionBackgroundFadeDuration,                        DEFAULT_BACKGROUND_FADE_DURATION_MS);            }            if (mSharedElementsUseOverlay == null) {                mSharedElementsUseOverlay = getWindowStyle().getBoolean(                        R.styleable.Window_windowSharedElementsUseOverlay, true);            }        }    }}

对上面的方法主要节点剖析

  •  mContentParent = generateLayout(mDecor);

推荐结合这篇博客Andriod中Style/Theme原理以及Activity界面文件选取过程浅析来看这个方法的源码

protected ViewGroup generateLayout(DecorView decor) {    // Apply data from current theme.    TypedArray a = getWindowStyle();    ...//根据window style设置window的属性    WindowManager.LayoutParams params = getAttributes();    // Non-floating windows on high end devices must put up decor beneath the system bars and    // therefore must know about visibility changes of those.    if (!mIsFloating && ActivityManager.isHighEndGfx()) {        if (!targetPreL && a.getBoolean(                R.styleable.Window_windowDrawsSystemBarBackgrounds,                false)) {            setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,                    FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());        }        if (mDecor.mForceWindowDrawsStatusBarBackground) {            params.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;        }    }    if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {        decor.setSystemUiVisibility(                decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);    }    if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion            >= android.os.Build.VERSION_CODES.HONEYCOMB) {        if (a.getBoolean(                R.styleable.Window_windowCloseOnTouchOutside,                false)) {            setCloseOnTouchOutsideIfNotSet(true);        }    }    if (!hasSoftInputMode()) {        params.softInputMode = a.getInt(                R.styleable.Window_windowSoftInputMode,                params.softInputMode);    }    if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,            mIsFloating)) {        /* All dialogs should have the window dimmed */        if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {            params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;        }        if (!haveDimAmount()) {            params.dimAmount = a.getFloat(                    android.R.styleable.Window_backgroundDimAmount, 0.5f);        }    }    if (params.windowAnimations == 0) {        params.windowAnimations = a.getResourceId(                R.styleable.Window_windowAnimationStyle, 0);    }    // The rest are only done if this window is not embedded; otherwise,    // the values are inherited from our container.    if (getContainer() == null) {        if (mBackgroundDrawable == null) {            if (mBackgroundResource == 0) {                mBackgroundResource = a.getResourceId(                        R.styleable.Window_windowBackground, 0);            }            if (mFrameResource == 0) {                mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);            }            mBackgroundFallbackResource = a.getResourceId(                    R.styleable.Window_windowBackgroundFallback, 0);            if (false) {                System.out.println("Background: "                        + Integer.toHexString(mBackgroundResource) + " Frame: "                        + Integer.toHexString(mFrameResource));            }        }        if (mLoadElevation) {            mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);        }        mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);        mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);    }    // Inflate the window decor.    int layoutResource;    int features = getLocalFeatures();    // System.out.println("Features: 0x" + Integer.toHexString(features));    if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {        layoutResource = R.layout.screen_swipe_dismiss;    } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {        if (mIsFloating) {            TypedValue res = new TypedValue();            getContext().getTheme().resolveAttribute(                    R.attr.dialogTitleIconsDecorLayout, res, true);            layoutResource = res.resourceId;        } else {            layoutResource = R.layout.screen_title_icons;        }        // XXX Remove this once action bar supports these features.        removeFeature(FEATURE_ACTION_BAR);        // System.out.println("Title Icons!");    } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0            && (features & (1 << FEATURE_ACTION_BAR)) == 0) {        // Special case for a window with only a progress bar (and title).        // XXX Need to have a no-title version of embedded windows.        layoutResource = R.layout.screen_progress;        // System.out.println("Progress!");    } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {        // Special case for a window with a custom title.        // If the window is floating, we need a dialog layout        if (mIsFloating) {            TypedValue res = new TypedValue();            getContext().getTheme().resolveAttribute(                    R.attr.dialogCustomTitleDecorLayout, res, true);            layoutResource = res.resourceId;        } else {            layoutResource = R.layout.screen_custom_title;        }        // XXX Remove this once action bar supports these features.        removeFeature(FEATURE_ACTION_BAR);    } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {        // If no other features and not embedded, only need a title.        // If the window is floating, we need a dialog layout        if (mIsFloating) {            TypedValue res = new TypedValue();            getContext().getTheme().resolveAttribute(                    R.attr.dialogTitleDecorLayout, res, true);            layoutResource = res.resourceId;        } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {            layoutResource = a.getResourceId(                    R.styleable.Window_windowActionBarFullscreenDecorLayout,                    R.layout.screen_action_bar);        } else {            layoutResource = R.layout.screen_title;        }        // System.out.println("Title!");    } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {        layoutResource = R.layout.screen_simple_overlay_action_mode;    } else {        // Embedded, so no decoration is needed.        layoutResource = R.layout.screen_simple;        // System.out.println("Simple!");    }    mDecor.startChanging();    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);    if (contentParent == null) {        throw new RuntimeException("Window couldn't find content container view");    }    if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {        ProgressBar progress = getCircularProgressBar(false);        if (progress != null) {            progress.setIndeterminate(true);        }    }    if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {        registerSwipeCallbacks();    }    // Remaining setup -- of background and title -- that only applies    // to top-level windows.    if (getContainer() == null) {        final Drawable background;        if (mBackgroundResource != 0) {            background = getContext().getDrawable(mBackgroundResource);        } else {            background = mBackgroundDrawable;        }        mDecor.setWindowBackground(background);        final Drawable frame;        if (mFrameResource != 0) {            frame = getContext().getDrawable(mFrameResource);        } else {            frame = null;        }        mDecor.setWindowFrame(frame);        mDecor.setElevation(mElevation);        mDecor.setClipToOutline(mClipToOutline);        if (mTitle != null) {            setTitle(mTitle);        }        if (mTitleColor == 0) {            mTitleColor = mTextColor;        }        setTitleColor(mTitleColor);    }    mDecor.finishChanging();    return contentParent;}

下面看看PhoneWindow的setContentView中的installDecor之后的方法

//有转场动画,则做一个动画特效。if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {    final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,            getContext());    transitionTo(newScene);} else {    //没有动画直接将布局inflate到mConentParent容器里    mLayoutInflater.inflate(layoutResID, mContentParent);}mContentParent.requestApplyInsets();//这个CallBack其实是在Activity里实现的final Callback cb = getCallback();//将布局改变以的事件回调给activityif (cb != null && !isDestroyed()) {    cb.onContentChanged();}

所以由以上的源码分析我们可知,activity的setContentView会将布局inflate到PhoneWindow的decorView里,WindowManager再将decorview添加显示出来 。

看完上述内容,你们对怎么浅析Activity的渲染过程有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

方法 源码 动画 过程 内容 布局 对象 是在 转场 面的 分析 明显 业务 事件 代码 会创 博客 原理 官方 容器 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 广州万易互联网科技有限公司 互联网科技活动banner 科技互联网龙头 互联网 科技公司 万易互联网科技 互联网科技股票 奔汉互联网科技 四川狮子座互联网科技 上海电发互联网科技有限公司 互联网经济与金融科技 阿大互联网科技有限公司 注册互联网科技公司经营范围大全 健康食品互联网创新科技园项目 互联网行业科技股 美国互联网科技实力 黑科技 体验场景 互联网大会 山东星卡互联网科技有限公司官网 互联网企业科技类企业如何做账 上海万顺科技互联网有限公司招聘 保山浩联互联网科技有限公司 A股互联网金融科技公司 互联网是不是新科技 互联网科技与金融科技 科技创新互联网企业 互联网科技公司招聘 世界互联网科技公司市值排名 互联网5g黑科技有哪些 健康食品互联网创新科技园项目 洛阳共同富裕互联网科技有限公司 国大互联网教育科技有限公司薪资
0