Android 窗口容器树(一)—— 窗口和窗口容器树

作者:无限进化日期:2026/5/4

窗口容器树系列文章:

  1. Android 窗口容器树(一)—— 窗口和窗口容器树
  2. Android 窗口容器树(二)—— 窗口容器树的构建

1. 什么是窗口?

在 Android 中,窗口不是 View,也不是某个单独的界面控件,而是系统层面对一块可显示 UI 内容的抽象管理单元

它至少有 3 个核心特征:

  1. 它有独立的 WindowManager.LayoutParams,用来描述类型、位置、大小、标志位等。
  2. 它最终会对应到 SurfaceControl / Surface,并交给 SurfaceFlinger 做最终合成。
  3. 它受 WindowManagerServiceWMS)统一管理,参与布局、输入、焦点、可见性等。

常见窗口包括:

  • Activity 主窗口
  • Dialog
  • PopupWindow
  • 状态栏
  • 导航栏
  • 输入法窗口
  • 壁纸窗口

窗口之所以会互相遮挡,本质上是因为它们有前后顺序,也就是常说的 Z-Order。在 WMSWindowContainer 源码里,子节点列表本身就是按 Z-Order 保存的:

1// List is in z-order as the children appear on
2// screen with the top-most window container at the tail of the list.
3

这句的意思是:同一个父容器下,mChildren 越靠后,视觉上越靠前。比如同一个 ActivityRecord 下面,主窗口通常在前面,后弹出的 DialogPanel 往往会排到更靠后的位置,所以会盖在主窗口上面。

37 层窗口

37 层 指的是 WindowManagerPolicy 定义的窗口策略 layer 编号范围。

源码中 getMaxWindowLayer() 返回 36,所以 layer 取值是 0 ~ 36,一共 37 个槽位。

系统会通过 getWindowLayerFromTypeLw() 先把不同 window type 映射到这 37 个策略 layer 中的某一个,再在 Android 14 中继续用它做 DisplayArea 分区,并作为 WindowState 计算基础显示层的输入。因此,37 层 说的是窗口类型的策略分层,不是最终 SurfaceFlinger 看到的真实显示图层。

image.png

2. 不同维度的 3 棵树

先把下面 3 个层次的树区分开:

2.1 第一棵树:逻辑窗口容器树

第一棵树是 WMSWindowContainer 管理树。本文后面提到“窗口容器树”“窗口管理树”,默认都指这棵树。

WindowContainer 管理树上的节点大多是 WindowContainer 及其子类,例如:

  • RootWindowContainer
  • DisplayContent
  • DisplayArea
  • TaskDisplayArea
  • Task
  • TaskFragment
  • ActivityRecord
  • WindowToken
  • WindowState

WindowContainer 管理树管的是“窗口对象之间的管理关系”,比如:

  • 谁是谁的父节点
  • 谁在谁上面
  • 配置怎么往下传
  • 可见性怎么往下传播
  • 动画和转场作用在哪一整组节点上

所以 WindowContainer 管理树的本质是:

它描述的是“谁管理谁”,不是“屏幕怎么切”,也不是“最终怎么显示”。

2.2 第二棵树:DisplayArea 切分树

第二棵树是 DisplayContent 内部的 DisplayArea 分区树。它做的事情很单纯,就是把一整块屏幕按层级语义和功能语义切成不同区域。

它主要解决的是:

  1. 按 layer 把屏幕切开
  2. 按功能把屏幕切开
  3. 给不同类型的窗口准备不同的挂载区域

比如在 Android 14 默认策略里,DisplayAreaPolicy 会构建出:

  • 应用任务所在的 TaskDisplayArea
  • 非应用窗口所在的 Tokens 区域
  • IME 相关区域
  • 放大镜、单手模式、刘海避让这类 feature 区域

所以 DisplayArea 树本质上描述的是:

屏幕被切成了哪些区,每一类窗口该落到哪个区。

它和第一棵树的本质区别是:

  • WindowContainer 树讲的是对象之间的管理关系
  • DisplayArea 树讲的是屏幕内部的区域划分关系

前者是在“管对象”,后者是在“分地盘”。

2.3 第三棵树:SurfaceControl / SurfaceFlinger 合成树

第三棵树是 SurfaceControl / SurfaceFlinger 显示树。到了这一层,前面那些逻辑关系和区域划分,才会变成真正能显示到屏幕上的图层关系。

它关心的不是“谁管理谁”,也不是“窗口该落哪个区”,而是:

  • 最终画面怎么叠加
  • 图层前后顺序怎么生效
  • 位置、裁剪、透明度、缩放怎么作用到屏幕
  • 动画 leash 怎么临时接管某一组内容

WindowContainer 树上的节点,最终想显示出来,必须继续走下面这条路径:

  1. 创建或复用 SurfaceControl
  2. 通过 SurfaceControl.Transaction 提交 layer、位置、裁剪、透明度、变换矩阵等状态
  3. SurfaceFlinger 在合成阶段把所有 Surface 叠加到一起

所以 SurfaceControl / SurfaceFlinger 显示树的本质是:

它描述的是“最终屏幕上怎么显示”。

它和前两棵树的本质区别是:

  • 第一棵树 WindowContainer 树:讲管理关系
  • 第二棵树 DisplayArea 树:讲分区关系
  • 第三棵树 SurfaceControl / SurfaceFlinger 树:讲显示关系

把三棵树连起来看,就是:

先在 WindowContainer 树里确定管理关系,再在 DisplayArea 树里确定落区,最后在 SurfaceControl / SurfaceFlinger 这一层确定真正的显示结果。

2.4 三棵树之间到底是什么关系?

可以把它们串成一条链:

1window type
2    -> policy layer
3    -> DisplayArea 分区
4    -> WindowContainer 树中的挂载位置
5    -> SurfaceControl 树中的实际 layer 和父子关系
6    -> SurfaceFlinger 最终合成
7

因此,最容易记住的结论是:

WindowContainer 树负责“管理”,DisplayArea 树负责“分区”,Surface 树负责“显示”。

三者强相关,但绝对不是同一棵树。

3. 窗口容器树

在讲每一个类之前,先从全局看一遍 Android 14 中最常见的单屏 WindowContainer 管理树结构。下面这张图画的是 WMS 用来管理窗口对象的那棵树,不是 DisplayArea 分区树,也不是 SurfaceFlinger 的最终显示树。

3.1 简化总图

1RootWindowContainer
2`-- DisplayContent
3    `-- RootDisplayArea (ANY)
4        |-- DisplayArea (BELOW_TASKS)
5        |   `-- DisplayArea.Tokens
6        |       `-- WindowToken
7        |           `-- WindowState
8        |
9        |-- TaskDisplayArea (ANY)
10        |   `-- Task (RootTask,类型仍按 ANY 容器链处理)
11        |       `-- Task / TaskFragment
12        |           `-- ActivityRecord
13        |               |-- WindowState (TYPE_BASE_APPLICATION)
14        |               |-- WindowState (TYPE_APPLICATION_STARTING)
15        |               `-- WindowState (Dialog / Panel / attached window)
16        |
17        `-- DisplayArea (ABOVE_TASKS)
18            |-- DisplayArea.Tokens
19            |   `-- WindowToken
20            |       `-- WindowState
21            `-- ImeContainer / IME 对应区域
22                `-- WindowToken
23                    `-- WindowState
24

这张 WindowContainer 管理树总图想表达 3 个核心事实:

  1. 整个设备最上层是 RootWindowContainer
  2. 每一块实际屏幕在这棵管理树里对应一个 DisplayContent
  3. 到了 DisplayContent 内部以后,这棵管理树会分成两大主路径:
    • 应用窗口路径:TaskDisplayArea -> Task -> TaskFragment -> ActivityRecord -> WindowState
    • 非应用窗口路径:DisplayArea.Tokens -> WindowToken -> WindowState

3.2 分叉方式

源码里 DisplayArea.TypeDisplayArea / Task 这条管理链大致分成 3 类:

  • BELOW_TASKS
  • ANY
  • ABOVE_TASKS

它们在源码里的含义可以直接对应为:

  • BELOW_TASKS:应用任务层之下的系统窗口区域
  • ANY:既能继续包含其他 DisplayArea,也能包含 WindowTokenTask 容器
  • ABOVE_TASKS:应用任务层之上的系统窗口区域

这里最容易误解的是:ANY 不是图里额外长出来的一条单独分支,而是一种“这个区域可以装什么”的类型标记。

例如这张图里:

  • RootDisplayAreaANY
  • TaskDisplayArea 也是 ANY
  • Task 在源码的 DisplayArea.Type.typeOf() 里也按 ANY 处理

所以 TaskDisplayArea -> RootTask -> Task / TaskFragment 这条应用任务链,本身就是落在 ANY 这类容器能力里的。

TaskDisplayArea 本身就是专门放应用任务的区域,所以在 WindowContainer 管理树里,应用窗口不会直接掉进普通 Tokens 区,而是单独走应用任务容器链。

3.3 易错点

ActivityRecord 在 Android 14 中直接继承 WindowToken

这意味着应用窗口的 token 和 ActivityRecord 是同一个对象,不是“ActivityRecord 下再套一个独立 WindowToken”。

应用窗口不直接挂在 DisplayArea.Tokens

DisplayArea.Tokens 主要承载的是非应用类 WindowToken,应用窗口要先进入任务体系,再进入 ActivityRecord,最后才到 WindowState

4. 从根到叶,节点详解

先抓住主线:

1WindowContainer
2-> RootWindowContainer
3-> DisplayContent
4-> RootDisplayArea / DisplayArea
5-> 应用分支或非应用分支
6-> WindowState
7

这一节只讲每一层“在树里负责什么”,不再展开无关旁支。

4.1 WindowContainer:所有节点的公共基类

源码定义:

1class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
2        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
3        InsetsControlTarget {
4    private WindowContainer<WindowContainer> mParent = null;
5    protected final WindowList<E> mChildren = new WindowList<E>();
6}
7

WindowContainer 是整棵管理树的基础设施,所有后续节点都共享它的 4 个核心能力:

  1. mParent / mChildren 维护父子关系
  2. mChildren 维护兄弟节点顺序
  3. 向下传播配置、可见性和动画状态
  4. 作为逻辑容器去绑定 SurfaceControl

其中最关键的是 mChildren。源码注释写得很明确:

1// List is in z-order as the children appear on
2// screen with the top-most window container at the tail of the list.
3

也就是说,mChildren 本身就是按 Z-Order 排好的,列表尾部的子节点在视觉上最靠前。WindowContainer 维护层级顺序,主要靠 addChild(...)positionChildAt(...) 这类方法完成。

4.2 RootWindowContainer:设备级根节点

源码定义:

1class RootWindowContainer extends WindowContainer<DisplayContent>
2        implements DisplayManager.DisplayListener {
3}
4

RootWindowContainer 是整台设备的根节点,它的直接子节点不是窗口,而是一块块屏幕对应的 DisplayContent

所以它负责的是设备级问题:

  • 管理所有 DisplayContent
  • 维护焦点屏幕、睡眠状态、旋转等全局状态
  • 作为 ATMWMS 协调显示行为的顶层入口

一句话说,RootWindowContainer 管的是“整台设备有多少块屏,每块屏的窗口体系怎么组织”。

4.3 DisplayContent:单块屏幕的根节点

源码定义:

1class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {
2}
3

DisplayContent 表示一块实际屏幕。到了这一层,分析对象就从“整台设备”变成了“某一块具体屏幕”。

它在这棵管理树里主要做两件事:

  1. 作为单屏窗口体系的根节点
  2. 管理单屏显示相关状态,例如焦点窗口、输入法目标、壁纸目标、转场和显示参数

同时它还维护 mTokenMap,把 IBinderWindowToken 关联起来,并持有 mWindowingLayermOverlayLayermInputOverlayLayer 等合成层入口。

所以 DisplayContent 既是屏幕根节点,也是单屏逻辑树和显示树的连接点。

4.4 RootDisplayAreaDisplayArea:先分区,再决定挂载路径

源码定义:

1public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
2}
3

到了 DisplayContent 下面,不会立刻挂具体窗口,而是先由 RootDisplayArea / DisplayArea 这一层决定“这个窗口应该落到哪一块区域”。

这里说的作用,指的是 RootDisplayArea / DisplayArea 这一层在整棵管理树里的作用:

  1. 按 layer 分区
  2. 按 feature 分区
  3. 为不同窗口类型准备稳定挂载点

也就是说,DisplayContent 先把屏幕交给 RootDisplayArea 管,RootDisplayArea 再根据窗口类型和 layer,把窗口分流到不同的 DisplayArea / Tokens / TaskDisplayArea 区域。

这里最关键的源码出自 RootDisplayArea 查找窗口落点的方法,也就是 findAreaForTokenInLayer() 最终调用的按 windowType 找区域逻辑:

1if (windowLayerFromType == APPLICATION_LAYER) {
2    throw new IllegalArgumentException(
3            "There shouldn't be WindowToken on APPLICATION_LAYER");
4}
5

这句的结论就是:普通 WindowToken 不能落在 APPLICATION_LAYER。所以从 DisplayArea 往下会分两条路:

  • 应用窗口:走任务体系
  • 非应用窗口:走 Tokens 体系

4.5 应用窗口路径:TaskDisplayArea -> Task / TaskFragment -> ActivityRecord

应用窗口路径可以先记成:

1TaskDisplayArea
2`-- Task
3    `-- TaskFragment
4        `-- ActivityRecord
5            `-- WindowState
6

这条路径里每一层负责的事情分别是:

  • TaskDisplayArea
    • 应用任务进入这块屏幕后的入口区域
    • 负责根任务顺序、焦点任务、启动落点
  • Task
    • 真正承载任务实体
    • 负责这一组 Activity 属于哪个任务
  • TaskFragment
    • 任务内部的再切分容器
    • 大屏、分栏、嵌入式布局都依赖它
  • ActivityRecord
    • 应用窗口分支的关键节点
    • 负责把任务容器切换到具体窗口容器

其中最重要的是 ActivityRecord。Android 14 源码定义:

1final class ActivityRecord extends WindowToken
2        implements WindowManagerService.AppFreezeListener {
3}
4

这意味着:

ActivityRecord 本身就是应用窗口对应的 WindowToken

应用窗口的主窗口、启动窗口、DialogPanel、attached window,都会挂到这个 ActivityRecord 下面。

4.6 非应用窗口路径:DisplayArea.Tokens -> WindowToken

非应用窗口路径更短:

1DisplayArea.Tokens
2`-- WindowToken
3    `-- WindowState
4

入口节点是 DisplayArea.Tokens

1public static class Tokens extends DisplayArea<WindowToken> {
2}
3

它承载的是非应用类窗口,例如:

  • 状态栏
  • 壁纸
  • 输入法
  • 系统弹窗
  • 辅助功能覆盖层

这些窗口不会进入 Task / TaskFragment / ActivityRecord,而是直接进入 WindowToken 分组。

4.7 WindowToken:窗口分组机制

源码定义:

1class WindowToken extends WindowContainer<WindowState> {
2    final IBinder token;
3    final int windowType;
4}
5

WindowToken 的核心作用就是“把一组窗口组织起来”。

它负责 4 件事:

  1. 标识这组窗口属于谁
  2. 决定这组窗口落在哪个区域和层级
  3. 作为权限校验和生命周期管理的单位
  4. 作为 WindowState 的直接父容器

对非应用窗口来说,WindowToken 直接承载这一组窗口;对应用窗口来说,这套能力被 ActivityRecord 继承过去了。

所以正确理解应该是:

WindowToken 是窗口分组机制;应用窗口用 ActivityRecord 继承这套机制,非应用窗口直接使用这套机制。

4.8 WindowState:树的最底层窗口实例

源码定义:

1class WindowState extends WindowContainer<WindowState>
2        implements WindowManagerPolicy.WindowState, InsetsControlTarget, InputTarget {
3}
4

WindowState 才是真正具体的窗口实例。比如一个 Activity 的主窗口、一个启动窗口、一个状态栏窗口,落到 WMS 里最终都会对应一个 WindowState。它持有窗口运行时最关键的信息,例如:

  • mAttrs
  • mToken
  • mActivityRecord
  • mBaseLayer
  • mSubLayer
  • mFrame
  • mSurfaceControl

它通常是容器树最底部的节点,但不一定是绝对叶子节点。比如 Activity 主窗口通常已经在路径末端了,但如果这个主窗口上又弹出了 DialogPanel,这个主窗口下面还会继续挂子窗口。attached window 场景下,源码会执行:

1parentWindow.addChild(this, sWindowSubLayerComparator);
2

这说明 WindowState 下面还可以继续挂子 WindowState。例如一个 Activity 主窗口下面,可以继续挂 TYPE_APPLICATION_PANEL 的面板窗口,或者 TYPE_APPLICATION_ATTACHED_DIALOG 的附着对话框。

因此,WindowState 最准确的定义是:

WMS 管理的最小窗口实例,也是最接近真实显示和输入分发的节点。比如点击屏幕时,输入系统最终要找到具体的 WindowState;窗口真正显示到屏幕上时,WMS 也是通过它去关联 SurfaceControl 和窗口属性。

5. 实际场景

5.1 普通 Activity 主窗口

1RootWindowContainer
2`-- DisplayContent
3    `-- TaskDisplayArea
4        `-- Task
5            `-- ActivityRecord
6                `-- WindowState (TYPE_BASE_APPLICATION)
7

这是最基础的应用路径。一个普通 Activity 显示到屏幕上时,最终会落到所属 TaskActivityRecord 下面,主窗口类型通常是 TYPE_BASE_APPLICATION

5.2 应用启动窗口

1Task
2`-- ActivityRecord
3    |-- WindowState (TYPE_APPLICATION_STARTING)
4    `-- WindowState (TYPE_BASE_APPLICATION)
5

这里最容易误解的是:启动窗口和主窗口不是同一个窗口。

  • 5.1 里的 TYPE_BASE_APPLICATION 是应用真正的主窗口
  • 这里的 TYPE_APPLICATION_STARTING 是系统为了冷启动过渡临时加上的启动窗口

所以在冷启动早期,同一个 ActivityRecord 下面可能短时间同时存在两个 WindowState

  1. 启动窗口:先显示,目的是尽快给用户一个可见界面
  2. 主窗口:应用真正绘制完成后接管显示

可以把它理解成:启动窗口是“占位过渡窗口”,主窗口才是“应用真正的内容窗口”。

5.3 Dialog

如果是应用内部弹出的 Dialog,一般仍然属于同一个 ActivityRecord

1Task
2`-- ActivityRecord
3    |-- WindowState (TYPE_BASE_APPLICATION)
4    `-- WindowState (TYPE_APPLICATION / TYPE_APPLICATION_ATTACHED_DIALOG)
5

这里的两个 WindowState 在这张图里可以先按“同属一个 ActivityRecord 的两个子窗口”来理解,也就是它们同属于一个应用窗口分支。

要注意两点:

  1. 这行 TYPE_APPLICATION / TYPE_APPLICATION_ATTACHED_DIALOG 说明 Dialog 常见有两种类型:
    • TYPE_APPLICATION
    • TYPE_APPLICATION_ATTACHED_DIALOG
  2. 如果是 attached dialog,它在更细的实际结构里还可能继续挂到某个父 WindowState 下面,而不只是简单地和主窗口并列

这说明 Dialog 并没有脱离当前 Activity 单独成树,而是仍然挂在同一个应用窗口分支里,只是窗口类型和挂载细节可能不同。

5.4 PopupWindow / Panel

这类 attached window 往往继续挂在某个父 WindowState 下:

1ActivityRecord
2`-- WindowState (主窗口)
3    `-- WindowState (TYPE_APPLICATION_PANEL)
4

它和上一节 Dialog 的区别,重点不在“是不是弹出来”,而在“是不是附着在父 WindowState 上”。

  • Dialog:常见理解是仍然属于同一个 ActivityRecord,有些场景下可以近似看成和主窗口同属一个应用窗口分支
  • PopupWindow / Panel:更典型的是 attached window,会直接挂在某个父 WindowState 下面

所以这类窗口最典型的特点不是“和主窗口平级”,而是“附着在某个父窗口下面”。因此它们除了受 ActivityRecord 管,还会继续受父 WindowState 的位置和 sub-layer 影响。

5.5 输入法窗口

1DisplayContent
2`-- DisplayArea.Tokens / IME 所在区域
3    `-- WindowToken (TYPE_INPUT_METHOD)
4        `-- WindowState
5

输入法不是应用任务的一部分,而是非应用窗口。它走的是 DisplayArea.Tokens -> WindowToken -> WindowState 这条路径,只是它会被放进专门的 IME 区域。

5.6 状态栏窗口

1DisplayContent
2`-- DisplayArea.Tokens
3    `-- WindowToken (TYPE_STATUS_BAR)
4        `-- WindowState
5

状态栏和输入法一样,也不属于任何 Task。它直接挂在非应用窗口分支,是一个典型的系统窗口场景。

5.7 壁纸窗口

1DisplayContent
2`-- DisplayArea.Tokens
3    `-- WindowToken (TYPE_WALLPAPER)
4        `-- WindowState
5

壁纸窗口也是非应用窗口,但它的层级通常更低,所以经常处在应用窗口下面,作为整个界面的背景层。

5.8 分屏场景下的两个应用任务

1RootWindowContainer
2`-- DisplayContent
3    `-- TaskDisplayArea
4        |-- Task
5        |   `-- ActivityRecord
6        |       `-- WindowState (左侧或上侧应用)
7        `-- Task
8            `-- ActivityRecord
9                `-- WindowState (右侧或下侧应用)
10

分屏场景不是多出一套新的窗口体系,而是在同一个 TaskDisplayArea 下同时存在多个 Task。这时要重点看的是 TaskDisplayArea 内部的任务顺序、焦点任务和分屏边界。

5.9 系统对话框或系统覆盖层

1DisplayContent
2`-- DisplayArea.Tokens
3    `-- WindowToken (TYPE_SYSTEM_DIALOG / TYPE_APPLICATION_OVERLAY ...)
4        `-- WindowState
5

像系统对话框、悬浮窗、某些辅助功能覆盖层,也都走非应用路径。区别不在于树形结构,而在于 window type、权限校验和最终 layer 高低不同。


Android 窗口容器树(一)—— 窗口和窗口容器树》 是转载文章,点击查看原文


相关推荐


【从0开始学设计模式-11| 外观模式】
我爱cope2026/4/24

概念 外观模式(Facade Pattern) 是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。 定义: 为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 外观模式又称为门面模式,它是一种对象结构型模式。外观模式是迪米特法则的一种具体实现,通过引入一个新的外观角色可以降低原有系统的复杂度,同时降低客户类与子


VPS 买回来第一天该干什么?我的开机必做清单
小墨同学boy2026/4/16

很多人买来第一台VPS可能不知道干什么,是到手之后直接装宝塔,然后部署一个WordPress 博客丢上去跑了两天。可能过几天你就会发现 auth.log 里全是暴力破解记录,SSH 端口没有改还是默认的 22,root 密码没有做修改还是简单的 8 数字。最离谱的是你没有一开始测试号,最后发现那台机器的网络在晚高峰根本不能用,到最后可以部署完了才发现的,前面装的东西全白费功夫。 所以我才要写这篇文章,介绍我的流程:新机器到手,不要一上来就按照服务,先按照我的固定流程把去设置一遍服务器。整个过程其


# KubeBlocks for MSSQL 高可用实现
小猿姐2026/4/8

背景 Microsoft SQL Server(MSSQL)是由微软开发的一款关系型数据库管理系统。最初仅支持在 Windows 平台上运行,自 2017 版本起开始支持 Linux 系统,这一变化为 MSSQL 的容器化部署提供了可能。 MSSQL 提供了名为 Availability Group(可用性组,下文简称AG) 的多数据库复制管理特性,该特性支持在多个节点上实现数据库的多副本冗余,从而提升数据可靠性和服务连续性。在 Windows 平台上,MSSQL 通过与 Windows Ser


AI时代,我们的任务不应沉溺于与 AI 聊天 - 🤔 从“对话式编程”迈向“数字软件工厂”
阿文WUTAI感话2026/3/31

2026年,AI辅助开发的正确打开方式 在 2026 年的今天,研发工程师已经意识到,AI 辅助开发不应只是零散的提示词,而是一套 有标准、有性能、有角色、有流程 的系统工程 。通过 OpenSpec、Everything Claude Code (ECC)、gstack 以及新增的 superpowers 的深度协同,我们可以构建起一套现代化的"数字软件工厂",让研发协作工作流与状态流转更加符合项目的确定性需求 一、核心概念:先对齐术语,避免鸡同鸭讲 要驾驭这套工厂,首先需要对齐底层的专业概


家政服务小程序预约上门服务维修保洁上门服务在线派单技师入驻-ym7K
2601_952013762026/3/22

一、后台管理端核心功能 1. 系统基础配置 提供基础设置、店铺管理、家政管理三大核心配置入口,支撑系统整体运行。支持家政分类管理,可灵活划分保洁、月嫂、家电维修等服务类型。 2. 家政服务发布与管理 发布家政服务: 选择对应家政分类,填写服务标题。配置所在区域、家政公司名称、联系人及联系电话。设定家政性质:免费预约、预约金、实价三种模式可选。通过富文本编辑器编辑服务详情,支持图文排版。 管理家政:对已发布服务进行编辑、上下架等操作。管理订单:查看、处理用户预约订单,跟踪服务进度。服


Codex 工程化实践指南:深入理解 AGENTS.md、SKILL.md 与 MCP
Lei_official2026/3/14

AI 就像自动驾驶,其价值并非让没摸过方向盘的新手上路开车,而在于为熟练的驾驶者节约精力和时间。 在 Codex 的设计中,有三个非常关键的概念: AGENTS.md SKILL.md MCP(Model Context Protocol) 如果把 Codex 看成一个 “AI 工程师”,那么这三个概念相当于: 概念角色AGENTS.md团队开发规范SKILL.md可复用工作流MCP外部系统接口 注意这里的“团队开发规范”不是指人类工程师所组成


端侧RAG实战指南
稀有猿诉2026/3/6

本文译自「On-Device RAG for App Developers: Embeddings, Vector Search, and Beyond」,原文链接medium.com/google-deve…,由Sasha Denisov发布于2026年2月21日。 我们已经探讨了离线 AI 代理的重要性 和如何通过函数调用赋予它们工具。现在,让我们通过赋予它们记忆——即使用 RAG(检索增强生成)搜索和检索你的私有数据——来完善整个图景。 当我开始构建 Flutter Gemma 时,


Gemini 3.1 Pro 正式发布:一次低调更新,还是谷歌的关键反击?
IvanCodes2026/2/25

今天凌晨,谷歌发布了新一代模型——Gemini 3.1 Pro 没有大型发布会,没有提前预热,甚至连宣传节奏都显得克制。 很多人会把它看作 Gemini 3 的小版本升级,但从目前披露的测试数据和演示能力来看,这更像是一次结构性强化,而不是简单的参数迭代。 如果说 Gemini 3 是谷歌重新回到核心竞争区间的标志,那么 Gemini 3.1 Pro,则明显带着更强的实战优化意味。 它在几个关键方向上给出了非常明确的信号:谷歌不只是追赶者。 性能升级:从可用到强势竞争 这次升


React 性能优化:图片懒加载
NEXT062026/2/17

引言 在现代 Web 应用开发中,首屏加载速度(FCP)和最大内容绘制(LCP)是衡量用户体验的核心指标。随着富媒体内容的普及,图片资源往往占据了页面带宽的大部分。如果一次性加载页面上的所有图片,不仅会阻塞关键渲染路径,导致页面长时间处于“白屏”或不可交互状态,还会浪费用户的流量带宽。 图片懒加载(Lazy Loading)作为一种经典的性能优化策略,其核心思想是“按需加载”:即只有当图片出现在浏览器可视区域(Viewport)或即将进入可视区域时,才触发网络请求进行加载。这一策略能显著减少首屏


【Linux】进程信号(上半)
Lsir10110_2026/2/8

当我们想要强行终止掉前台进程的时候,只需要按下Ctrl+c即可,但是Ctrl+c是如何精准杀掉前台进程的? 一、信号概念 1.如何理解信号 假设点了一份外卖,外卖员到了楼下会给你发信息或者打电话,那么这通电话或者这个信息就是信号,也就是用来提醒你需要去做某事的一种通知手段。那么对照Linux系统,信号就是内核向进程发送的通知,提醒进程需要去完成某个任务。 2.信号的特点 对照外卖例子,当点完外卖,我们肯定不会一直在门口等着外卖员,而是先忙手中的事情,比如打游戏,那么这个过程就叫做异步

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客