文章目录
一、概述
在 Android 系统中,Activity、Window 和 View 是构建用户界面的核心组件,它们之间的关系紧密且层次分明。理解它们的源码层级关系对于深入掌握 Android UI 机制至关重要。
二、核心概念
- Activity: 代表一个屏幕,是用户与应用交互的单一焦点。它是四大组件之一,负责管理 UI 的生命周期。
- Window: 是一个抽象类,代表一个具有装饰(如状态栏、标题栏)和管理视图层级的顶级窗口。
Window是View的直接管理者,负责提供一个View树可以依附的容器。PhoneWindow是其在 Android 中的具体实现。 - View: 所有 UI 组件的基类。
View是屏幕上的一块矩形区域,负责绘制和事件处理。ViewGroup是View的子类,可以包含其他View,形成视图树(View Hierarchy)。
三、架构和工作原理
用一句话概括三者关系:
一个
Activity拥有一个Window(通常是PhoneWindow),这个Window拥有一个作为根视图的DecorView,而开发者通过setContentView()设置的View(或View树)则被添加到DecorView内部的一个特定容器 (mContentParent) 中。
1.层级架构图:
Android System
|
v
Activity
| (持有 mWindow)
v
Window (PhoneWindow)
| (持有 mDecor)
v
DecorView (根视图)
|
-----------------------------------------------------
| | |
状态栏/标题栏等系统装饰 mContentParent (FrameLayout) 其他装饰视图
|
v
开发者 setContentView 的布局 (View 树)
|
--------------------------------
| | |
TextView Button ImageView
(子 View) (子 View) (子 View)
2.核心要点
- Activity 是管理者: 它负责生命周期,但不直接管理 UI 绘制。它通过
Window间接管理 UI。 - Window 是桥梁: 它是
Activity和View之间的桥梁。Activity将 UI 相关的操作(如setContentView)委托给Window。 - DecorView 是根:
DecorView是整个 Window 视图树的根节点,由PhoneWindow创建和管理。它包裹了系统 UI 和应用内容。 - mContentParent 是内容容器: 这是开发者真正可以控制的区域。
setContentView()设置的布局最终都成为mContentParent的子视图。 - 源码调用链:
Activity.setContentView()->PhoneWindow.setContentView()->PhoneWindow.installDecor()(创建DecorView和mContentParent) ->LayoutInflater.inflate()(将布局添加到mContentParent)。

四、源码级解析
下面我们通过源码来详细拆解这个关系链。
1. 关系的起点:Activity 的创建和 Window 的附着
一切的起点从 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 方法。
2. Activity.attach():Window 的创建与关联
// 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();
}
在这里,我们清晰地看到:
- Activity 持有一个
PhoneWindow(Window 的唯一实现类)实例mWindow。 PhoneWindow被创建时,传入了this,即当前 Activity 的引用。- Activity 将自己设置为 Window 的 Callback (
mWindow.setCallback(this)),这样窗口级别的事件(如按键、菜单、屏幕触摸)就可以传递到 Activity。 - Activity 通过
mWindow获取了WindowManager并持有。
3. setContentView():View 的创建与添加
当我们通常在 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 设置)
4. 视图的显示:Window 与 WindowManager
创建好视图树后,如何将它显示到屏幕上?这发生在 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。
五、关系图与总结
1. 关系总结
-
Activity & Window
- 一对一: 每个
Activity都持有一个PhoneWindow对象。 - 管理者与被管理者:
Activity负责Window的生命周期和事件回调。Window是Activity的 UI 承载器。
- 一对一: 每个
-
Window & View
- 一对多(树形): 一个
Window持有一个根视图DecorView,DecorView内部包含一个ContentView,我们自己的布局是ContentView的子视图。 - 容器与内容:
Window是视图的容器,它定义了窗口的样式和行为框架(如标题栏),而View是具体显示的内容。
- 一对多(树形): 一个
-
Activity & View
- 间接关系:
Activity通过Window来管理和控制View。Activity不直接持有View,但可以通过setContentView和findViewById来间接操作View。findViewById内部也是通过Window来查找DecorView,再在DecorView中查找目标View。
- 间接关系:
2.关系图
完整流程链:
Activity (创建和管理) -> PhoneWindow (承载) -> DecorView (根容器) -> ContentView (内容容器) -> Your View Hierarchy (你的 UI) -> ViewRootImpl (布局、绘制、通信) -> WMS (系统级窗口管理) -> SurfaceFlinger (最终渲染到屏幕)。
646

被折叠的 条评论
为什么被折叠?



