
在 Android 系统中,Activity、Window 和 View 是构建用户界面的核心组件,它们之间的关系紧密且层次分明。理解它们的源码层级关系对于深入掌握 Android UI 机制至关重要。
Window 是 View 的直接管理者,负责提供一个 View 树可以依附的容器。PhoneWindow 是其在 Android 中的具体实现。View 是屏幕上的一块矩形区域,负责绘制和事件处理。ViewGroup 是 View 的子类,可以包含其他 View,形成视图树(View Hierarchy)。用一句话概括三者关系:
一个
Activity拥有一个Window(通常是PhoneWindow),这个Window拥有一个作为根视图的DecorView,而开发者通过setContentView()设置的View(或View树)则被添加到DecorView内部的一个特定容器 (mContentParent) 中。
Android System
|
v
Activity
| (持有 mWindow)
v
Window (PhoneWindow)
| (持有 mDecor)
v
DecorView (根视图)
|
-----------------------------------------------------
| | |
状态栏/标题栏等系统装饰 mContentParent (FrameLayout) 其他装饰视图
|
v
开发者 setContentView 的布局 (View 树)
|
--------------------------------
| | |
TextView Button ImageView
(子 View) (子 View) (子 View)Window 间接管理 UI。Activity 和 View 之间的桥梁。Activity 将 UI 相关的操作(如 setContentView)委托给 Window。DecorView 是整个 Window 视图树的根节点,由 PhoneWindow 创建和管理。它包裹了系统 UI 和应用内容。setContentView() 设置的布局最终都成为 mContentParent 的子视图。Activity.setContentView() -> PhoneWindow.setContentView() -> PhoneWindow.installDecor() (创建 DecorView 和 mContentParent) -> LayoutInflater.inflate() (将布局添加到 mContentParent)。
下面我们通过源码来详细拆解这个关系链。
一切的起点从 ActivityThread#performLaunchActivity 方法开始,当系统要启动一个 Activity 时,会调用这个方法。
// ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// ... 创建 Activity 实例 ...
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
// ...
} catch (Exception e) {
// ...
}
try {
// ... 创建 Application 并调用 onCreate ...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
// ... 关联 Context 等 ...
// **核心方法:调用 activity.attach()**
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);
// ... 调用 onCreate ...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
// ...
}
}
// ...
}关键就在于 activity.attach() 方法。我们进入 Activity#attach 方法。
// Activity.java
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, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
// ... 其他初始化 ...
// **1. 创建并初始化唯一的 Window 对象**
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this); // 将 Activity 设置为 Window 的 Callback,用于接收事件分发(如按键、触摸)
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
// ... 其他初始化 ...
// **2. 为 Window 设置 WindowManager**
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());
}
// **3. Activity 持有 WindowManager 的引用**
mWindowManager = mWindow.getWindowManager();
}在这里,我们清晰地看到:
PhoneWindow(Window 的唯一实现类)实例 mWindow。PhoneWindow 被创建时,传入了 this,即当前 Activity 的引用。mWindow.setCallback(this)),这样窗口级别的事件(如按键、菜单、屏幕触摸)就可以传递到 Activity。mWindow 获取了 WindowManager 并持有。当我们通常在 Activity 的 onCreate 中调用 setContentView(R.layout.activity_main) 时,发生了什么?
// Activity.java
public void setContentView(@LayoutRes int layoutResID) {
// **委托给 Window 的 setContentView 方法**
getWindow().setContentView(layoutResID);
// 初始化 ActionBar(如果存在)
initWindowDecorActionBar();
}getWindow() 返回的就是我们刚刚创建的 PhoneWindow 对象。我们进入 PhoneWindow#setContentView。
// PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
// **1. 核心方法:installDecor()**
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
// **2. 将我们的布局文件 inflate 到 mContentParent 中**
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()) {
// **3. 通知 Activity 内容已经改变**
cb.onContentChanged();
}
// ...
}关键方法是 installDecor()。
PhoneWindow.installDecor():创建 DecorView 和 ContentParent
// PhoneWindow.java
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// **1. 生成 DecorView**
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) {
// **2. 生成 mContentParent**
mContentParent = generateLayout(mDecor);
// ... 根据 Theme 和 Feature 设置标题栏、状态栏等 ...
}
}generateDecor(-1):创建了 DecorView,它是 FrameLayout 的子类,是整个窗口的根视图。generateLayout(mDecor):根据主题和 Requested Feature(如 FEATURE_NO_TITLE),选择一个预定义的屏幕布局(如 R.layout.screen_simple),并将其加载到 DecorView 中。这个布局文件里会包含一个最重要的 ViewGroup,其 ID 为 android.R.id.content。这个方法会找到这个 ViewGroup 并返回,赋值给 mContentParent。所以,mContentParent 就是我们通过 setContentView 传进去的布局文件的父容器。
关系链到这里变成了: Activity -> PhoneWindow -> DecorView -> ContentParent (android.R.id.content) -> Your Custom Layout (通过 setContentView 设置)
创建好视图树后,如何将它显示到屏幕上?这发生在 ActivityThread#handleResumeActivity 中。
// ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
// ... 调用 onStart(), onResume() ...
final Activity a = r.activity;
// ...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
// **获取 DecorView**
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
// **获取 WindowManager**
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
// ...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// **核心:将 DecorView 添加到 WindowManager 中!**
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
}
// ...
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
// ... 最终让 DecorView 可见 ...
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
}a.getWindowManager() 返回的就是在 attach() 方法中设置的 mWindowManager。wm.addView(decor, l) 这行代码是视图显示到屏幕上的最终步骤。这里的 WindowManager 的实际实现是 WindowManagerImpl。WindowManagerImpl.addView() 会创建一个 ViewRootImpl 对象。
ViewRootImpl 是连接 Window 和 WMS(WindowManagerService)的桥梁。
View 的测量、布局、绘制。Choreographer 来管理 VSync 信号,安排渲染工作。Binder 与 WMS 通信,管理窗口的状态(如焦点、位置、动画等)。View。Activity 都持有一个 PhoneWindow 对象。Activity 负责 Window 的生命周期和事件回调。Window 是 Activity 的 UI 承载器。Window 持有一个根视图 DecorView,DecorView 内部包含一个 ContentView,我们自己的布局是 ContentView 的子视图。Window 是视图的容器,它定义了窗口的样式和行为框架(如标题栏),而 View 是具体显示的内容。Activity 通过 Window 来管理和控制 View。Activity 不直接持有 View,但可以通过 setContentView 和 findViewById 来间接操作 View。findViewById 内部也是通过 Window 来查找 DecorView,再在 DecorView 中查找目标 View。

完整流程链:
Activity (创建和管理) -> PhoneWindow (承载) -> DecorView (根容器) -> ContentView (内容容器) -> Your View Hierarchy (你的 UI) -> ViewRootImpl (布局、绘制、通信) -> WMS (系统级窗口管理) -> SurfaceFlinger (最终渲染到屏幕)。