热点
性能工程师:五大策略优化工具链,建站效能跃升,reasoning_content:我们要求以性能工程师的口吻,写一个与“技术、科技”相关,关于[建站效能跃升:掌握优化工具链的五大核心策略]的标题直接输出一个标题,不要加说明提示等信息简短精炼,字数控制在30字以内nn关键词:性能工程师、技术科技、建站效能跃升、优化工具链、五大核心策略nn可以设计的从性能工程师视角,突出工具链优化、提升建站效能例如:性能工程师秘笈:五大策略重塑建站工具链效能但需要简短或者:建站效能跃升:性能工程师的五大工具链核心策略字数可能略超nn注意标题要吸引人,符合性能工程师口吻,专业感考虑:五步优化工具链,建站效能跃升指南但需要包含“性能工程师”nn或者直接:性能工程师:五大核心策略优化建站工具链nn字数:性能工程师:五大核心策略优化建站工具链(共17字)可以nn或者更简洁:建站效能跃升:性能工程师五大工具链策略(15字)nn但原主题是“掌握优化工具链的五大核心策略”,所以最好体现“掌握”可以考虑:性能工程师:掌握五大工具链策略,建站效能跃升但字多nn权衡后,推荐:性能工程师:五大策略优化工具链,建站效能跃升(18字)或者:建站效能跃升:性能工程师五大核心工具链策略(17字)nn注意“掌握”可省略最终输出一个标题
多端适配全流程:高效建站方案技术详解,reasoning_content:我们要求以开发工程师的口吻,写一个与技术、科技相关,关于[全流程策划:多端建站高效适配方案详解]的标题直接输出一个标题,不要加说明提示等信息简短精炼,字数控制在30字以内nn需要体现开发工程师视角,技术、科技感核心是全流程策划:多端建站高效适配方案详解,但标题要浓缩可能的关键词:多端适配、高效方案、全流程、开发实战、架构策略等nn想到一些标题如:多端适配全流程实战:高效建站方案解析 但字数可能超?数一下:多端适配全流程实战:高效建站方案解析,共18个字(包括冒号)可以更精炼或者从规划到部署:多端适配高效方案详解 但字数也差不多nn也可以直接:全流程策划:多端建站高效适配方案 但缺少详解或者多端建站高效适配全流程方案详解 共15字但需要体现开发工程师口吻,比如实战、架构、原理等考虑多端适配全流程:高效建站方案技术解析 19字nn为了更简短:多端适配高效方案全流程详解 11字,但不够完整或者多端建站高效适配全流程方案 13字nn参考要求是全流程策划:多端建站高效适配方案详解,原题已有冒号可以保留原题但精简?原题18字(包括冒号?全流程策划:多端建站高效适配方案详解 一共17个汉字+一个冒号=18字符)其实可以直接用这个?但要求以开发工程师的口吻,原题已经算策划类,可能不够技术感可以加技术词汇nn最好控制在30字以内,很宽松可以写:多端建站高效适配:全流程方案与实战详解 共16字或者全流程策划:多端建站高效适配方案技术深解 17字或者工程师视角:多端建站高效适配全流程方案 16字nn我倾向于:多端适配全流程:高效建站方案技术详解 16字直接输出这个
容器化与智能编排:系统无碍新范式,reasoning_content:我们要求以全栈工程师的口吻,写一个与“技术、科技”相关,关于“容器化部署与智能编排:构建系统无碍新范式”的标题直接输出一个标题,不要加说明,简短精炼,30字以内nn全栈工程师口吻:可能偏向于实战、工程化、技术深度,也可以有“我”、“我们”视角,但标题通常不需要人称也可以结合“容器化”、“智能编排”、“无碍”(无障碍?或无缝?可能是“无碍”意为无障碍、无故障?)原题“构建系统无碍新范式”可能意思是构建系统无故障/无缝的新范式所以标题要体现容器化部署+智能编排,并突出新范式nn构思:例如“容器化+智能编排:系统无碍新范式” 但字数较多或者“容器化部署与智能编排:构建无碍系统新范式” 但超过30字?数一下:容器化部署与智能编排:构建无碍系统新范式 – 共18字?中文字符:容器化部署与智能编排:构建无碍系统新范式 -> 容器化部署(4) 与(1) 智能编排(4) :(1) 构建(2) 无碍(2) 系统(2) 新范式(3) 总共4+1+4+1+2+2+2+3=19字,在30以内但原题要求“简短精炼”,可以更精炼例如“容器+智能编排:系统无碍新范式” 13字或者“容器化部署+智能编排:无碍系统新范式” 15字nn全栈工程师口吻:可能喜欢用“实战”、“指南”、“之道”等,但标题直接给出即可我选择“容器化部署+智能编排:系统无碍新范式” 共15字,看是否更精炼?或者去掉“部署”:“容器化+智能编排:系统无碍新范式” 13字但“容器化”本身包含部署概念?可能可以或者“容器化与智能编排:系统无碍新范式” 14字最终决定使用“容器化与智能编排:系统无碍新范式”注意不要加引号,直接输出
UI测试工程师的Windows运行库配置与开发环境全攻略,reasoning_content:我们要求以UI测试工程师的口吻写一个与技术、科技相关,关于[Windows运行库配置与管理:轻松搭建开发环境全攻略]的标题需要直接输出标题,不要加说明字数30字以内,简短精炼nn思路:UI测试工程师口吻,可能注重稳定性、兼容性、环境配置等可以结合运行库、配置、开发环境、攻略等词例如:UI测试工程师必看:Windows运行库配置一步到位 但需要更精简或者Windows运行库配置:UI测试环境搭建指南注意不要超过30字nn尝试:UI测试工程师:Windows运行库配置与开发环境搭建全攻略 字数?数一下:UI测试工程师:Windows运行库配置与开发环境搭建全攻略 – 共22个汉字+标点?实际汉字:UI(2字母算2个? 通常中文字数按汉字算,但UI是英文字母,题目说字数控制在30字以内,一般指汉字或字符?安全起见,用中文字符可以写成UI测试工程师即4个汉字+2个字母?严格来说,可以把UI视为两个字符为了简洁,可以写UI测试工程师共5个字符(U、I、测、试、工、程、师?不对,U,I,测,试,工,程,师 7个字符但通常算字数时英文字母算半个或一个?稳妥起见,用全中文表达,比如界面测试工程师但原要求是UI测试工程师,最好保留UInn可以写:【UI测试工程师】Windows运行库配置与环境搭建攻略 – 数一下:【UI测试工程师】Windows运行库配置与环境搭建攻略 – 汉字+符号:共? 【(1)、U(1)、I(1)、(1)、测(1)、试(1)、工(1)、程(1)、师(1)、】(1)、W(1)、i(1)、n(1)、d(1)、o(1)、w(1)、s(1)、运(1)、行(1)、库(1)、配(1)、置(1)、与(1)、环(1)、境(1)、搭(1)、建(1)、攻(1)、略(1) – 共29个字符?还有空格?实际有29个字符,但包含英文字母和符号可能超30?再算:符号算一个,英文字母每个算一个,总共:括号两个, UI两个, 汉字:测试工程师(4) Windows(7) 运行库配置与环境搭建攻略(13) 合计2+2+4+7+13=28加上中间可能没有空格28个,可以但【】可能不必要更简洁:nnUI测试工程师:Windows运行库配置与开发环境搭建 字数:UI测试工程师(7字符) :(1) Windows(7) 运行库配置与开发环境搭建(13) 合计7+1+7+13=28,可以但缺少全攻略意味或者轻松搭建nn另一个:Windows运行库配置:UI测试工程师开发环境搭建指南 字数:Windows运行库配置(11) :(1) UI测试工程师(7) 开发环境搭建指南(9) 合计11+1+7+9=28也不错nn最终选择简洁且有全攻略的考虑:UI测试工程师的Windows运行库配置与开发环境全攻略 字数:UI测试工程师的(8) Windows运行库配置与开发环境全攻略(16) 合计24字OKnn注意:要直接输出,不要加说明所以输出这个
16 9 月 2026, 周三

理性分析Window Activity DecorView以及ViewRoot之间关联

前言
Activity和window,DecorView ,viewRoot是什么关系
 
今天我们就来讲解下,这样你在面试时候,游刃有余;
 
一、基本概念介绍
1、Activity
Activity负责控制生命周期和处理事件;
负责统筹视图的添加与显示,以及通过一些回调方法与Window和View进行交互;
一个Activity包含一个Window,真正控制视图的是Window,Window才是真正代表一个窗口;
统筹视图的添加与显示,通过回调与Window和View进行交互;
2、Window
Window是视图的承载者,是一个抽象类;
Activity中持有的实际上是Window的子类PhoneWindow;
Window通过WindowManager加载了一个DecorView到Window中,并将DecorView交给了ViewRoot;
3、DecorView
DecorView的父类是FrameLayout,是Android View树的根节;
内部包含一个竖直方向的LinearLayout,它有上下三个部分,上面是个ViewStub,延迟加载的视图(ActionBar,根据Theme设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。setContentView所设置的布局文件其实就是被加到内容栏之中的;
ViewGroup content = (ViewGroup)findViewById(android.R.id.content);
ViewGroup rootView = (ViewGroup) content.getChildAt(0)
 4、ViewRoot
控制View的事件处理和逻辑处理;
ViewRoot子类是ViewRootImpl类,它是连接WindowManagerService和DecorView的纽带,View的三大流程(测量(measure),布局(layout),绘制(draw))均通过ViewRoot来完成;
ViewRoot并不属于View树的一部分。从源码实现上来看,它既非View的子类,也非View Group,但它实现了ViewParent接口,这让它可以作为View的名义上的父视图;
RootView继承了Handler类,可以接收事件并分发;
Android的所有触屏事件、按键事件、界面刷新等事件都是通过ViewRoot进行分发的;
 
 
二、DecorView的创建整个流程详解
1、attach
Activity的setContentView()开始
 
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
可以看到实际上是交给Window来装载视图的;
 
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) {
…………………………………………………………
        mWindow = new PhoneWindow(this, window);//创建一个Window对象
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);//设置回调,向Activity分发点击或状态改变等事件
        mWindow.setOnWindowDismissedCallback(this);
        ………………………………………………………..
        mWindow.setWindowManager(
        (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
        mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//给Window设置WindowManager对象
        …………………………………………………………..
}
在Activity的attach方法中生成了PhoneWindow的实例;
 
有了Window对象,接下来就将DecorView加载到Window中;
 
2、setContentView
public void setContentView(int layoutResID) {
    if (mContentParent == null) {//mContentParent为空,创建一个DecroView
    installDecor();
    } else {
        mContentParent.removeAllViews();//mContentParent不为空,删除其中的View
    }
    mLayoutInflater.inflate(layoutResID, mContentParent);//为mContentParent添加子View,即Activity中设置的布局文件
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();//回调通知,内容改变
    }
}
mContentParent就是ContentView所对应的的FrameLayout;
 
Activity的setContentView的流程大致可以总结为:
 
Activity首先在Attach方法中生成了PhoneWindow的实例;
 
在setContentView中直接交给Window来装载视图,先在PhoneWindow中创建了一个DecroView;
 
其中创建的过程中可能根据Theme不同,加载不同的布局格式,即Activity中设置的布局;
 
3、installDecor
private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor(); //生成DecorView
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor); // 为DecorView设置布局格式,并返回mContentParent
        …
        }  
    }
}
protected DecorView generateDecor() {
    return new DecorView(getContext(), -1);
}
很简单,创建了一个DecorView;
 
再看generateLayout;
 
4、generateLayout
protected ViewGroup generateLayout(DecorView decor) {
    // 从主题文件中获取样式信息
    TypedArray a = getWindowStyle();
    ……………….
    if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
        requestFeature(FEATURE_NO_TITLE);
    } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
        // Don't allow an action bar if there is no title.
        requestFeature(FEATURE_ACTION_BAR);
    }
    …………….
    // 根据主题样式,加载窗口布局
    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(…){
        …
    }
    View in = mLayoutInflater.inflate(layoutResource, null);//加载layoutResource
    //往DecorView中添加子View,即文章开头介绍DecorView时提到的布局格式,那只是一个例子,根据主题样式不同,加载不同的布局。
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
    mContentRoot = (ViewGroup) in;
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);// 这里获取的就是mContentParent
    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.
    …
    return contentParent;
 先从主题中获取样式,然后根据样式;
加载对应的布局到DecorView中,然后从中获取mContentParent;
获得到之后,可以回到上面的代码,为mContentParent添加View,即Activity中的布局;
5、DecorView的显示
将DecorView建立起来,通过setContentView设置的界面,如何在onResume后对用户可见,需要从ActivityThread说起;
 
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //就是在这里调用了Activity.attach(),接着调用了Activity.onCreate()和Activity.onStart()生命周期,
    //但是由于只是初始化了mDecor,添加了布局文件,还没有把
    //mDecor添加到负责UI显示的PhoneWindow中,所以这时候对用户来说,是不可见的
    Activity a = performLaunchActivity(r, customIntent);
    ……
    if (a != null) {
    //这里面执行了Activity.onResume()
    handleResumeActivity(r.token, false, r.isForward,
                        !r.activity.mFinished && !r.startsNotResumed);
    if (!r.activity.mFinished && r.startsNotResumed) {
        try {
                r.activity.mCalled = false;
                //执行Activity.onPause()
                mInstrumentation.callActivityOnPause(r.activity);
                }
        }
    }
}
重点看下handleResumeActivity(),在这其中,DecorView将会显示出来,同时重要的一个角色;ViewRoot也将登场;
 
6、handleResumeActivity
final void handleResumeActivity(IBinder token, boolean clearHide,  
                                boolean isForward, boolean reallyResume) {
    //这个时候,Activity.onResume()已经调用了,但是现在界面还是不可见的
    ActivityClientRecord r = performResumeActivity(token, clearHide);
    if (r != null) {
        final Activity a = r.activity;
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            //decor对用户不可见
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            if (a.mVisibleFromClient) {
                a.mWindowAdded = true;
                //被添加进WindowManager了,但是这个时候,还是不可见的
                wm.addView(decor, l);
            }
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
                //在这里,执行了重要的操作,使得DecorView可见
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }
        }
    }
}
当我们执行了Activity.makeVisible()方法之后,界面才对我们是可见的;
 
void makeVisible() {
   if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());//将DecorView添加到WindowManager
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);//DecorView可见
}
 到此DecorView便可见,显示在屏幕中;
但是在这其中,wm.addView(mDecor, getWindow().getAttributes());
起到了重要的作用,因为其内部创建了一个ViewRootImpl对象,负责绘制显示各个子View;
具体来看addView()方法,因为WindowManager是个接口,具体是交给WindowManagerImpl来实现的;
7、addView
public final class WindowManagerImpl implements WindowManager {     
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    …
    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
}
交给WindowManagerGlobal 的addView()方法去实现;
public void addView(View view, ViewGroup.LayoutParams params,
                    Display display, Window parentWindow) {
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    ……
    synchronized (mLock) {
        ViewRootImpl root;
        //实例化一个ViewRootImpl对象
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }
    ……
    try {
        //将DecorView交给ViewRootImpl
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
    }
}
 看到其中实例化了ViewRootImpl对象,然后调用其setView()方法;
其中setView()方法经过一些列折腾,最终调用了performTraversals()方法,完成绘制,最终界面才显示出来;
 
 
总结
Activity就像个控制器,不负责视图部分。Window像个承载器,装着内部视图;
DecorView就是个顶层视图,是所有View的最外层布局;
ViewRoot像个连接器,负责沟通,通过硬件的感知来通知视图,进行用户之间的交互;

dawei

您错过了

性能工程师:五大策略优化工具链,建站效能跃升,reasoning_content:我们要求以性能工程师的口吻,写一个与“技术、科技”相关,关于[建站效能跃升:掌握优化工具链的五大核心策略]的标题直接输出一个标题,不要加说明提示等信息简短精炼,字数控制在30字以内nn关键词:性能工程师、技术科技、建站效能跃升、优化工具链、五大核心策略nn可以设计的从性能工程师视角,突出工具链优化、提升建站效能例如:性能工程师秘笈:五大策略重塑建站工具链效能但需要简短或者:建站效能跃升:性能工程师的五大工具链核心策略字数可能略超nn注意标题要吸引人,符合性能工程师口吻,专业感考虑:五步优化工具链,建站效能跃升指南但需要包含“性能工程师”nn或者直接:性能工程师:五大核心策略优化建站工具链nn字数:性能工程师:五大核心策略优化建站工具链(共17字)可以nn或者更简洁:建站效能跃升:性能工程师五大工具链策略(15字)nn但原主题是“掌握优化工具链的五大核心策略”,所以最好体现“掌握”可以考虑:性能工程师:掌握五大工具链策略,建站效能跃升但字多nn权衡后,推荐:性能工程师:五大策略优化工具链,建站效能跃升(18字)或者:建站效能跃升:性能工程师五大核心工具链策略(17字)nn注意“掌握”可省略最终输出一个标题

多端适配全流程:高效建站方案技术详解,reasoning_content:我们要求以开发工程师的口吻,写一个与技术、科技相关,关于[全流程策划:多端建站高效适配方案详解]的标题直接输出一个标题,不要加说明提示等信息简短精炼,字数控制在30字以内nn需要体现开发工程师视角,技术、科技感核心是全流程策划:多端建站高效适配方案详解,但标题要浓缩可能的关键词:多端适配、高效方案、全流程、开发实战、架构策略等nn想到一些标题如:多端适配全流程实战:高效建站方案解析 但字数可能超?数一下:多端适配全流程实战:高效建站方案解析,共18个字(包括冒号)可以更精炼或者从规划到部署:多端适配高效方案详解 但字数也差不多nn也可以直接:全流程策划:多端建站高效适配方案 但缺少详解或者多端建站高效适配全流程方案详解 共15字但需要体现开发工程师口吻,比如实战、架构、原理等考虑多端适配全流程:高效建站方案技术解析 19字nn为了更简短:多端适配高效方案全流程详解 11字,但不够完整或者多端建站高效适配全流程方案 13字nn参考要求是全流程策划:多端建站高效适配方案详解,原题已有冒号可以保留原题但精简?原题18字(包括冒号?全流程策划:多端建站高效适配方案详解 一共17个汉字+一个冒号=18字符)其实可以直接用这个?但要求以开发工程师的口吻,原题已经算策划类,可能不够技术感可以加技术词汇nn最好控制在30字以内,很宽松可以写:多端建站高效适配:全流程方案与实战详解 共16字或者全流程策划:多端建站高效适配方案技术深解 17字或者工程师视角:多端建站高效适配全流程方案 16字nn我倾向于:多端适配全流程:高效建站方案技术详解 16字直接输出这个