稀有猿诉

十年磨一剑,历炼出锋芒,说话千百句,不如码二行。

探究Android Views、Flutter和Compose如何渲染你的UI

本文译自「One Tap, Three Machines: How Android Views, Flutter, and Compose Actually Render Your UI」,原文链接https://medium.com/proandroiddev/one-tap-three-machines-how-android-views-flutter-and-compose-actually-render-your-ui-ad31c30ec279,由Angelina Andronova发布于2026年7月16日。

_Android Native vs Flutter vs KMP — 本系列文章对比了三种移动技术栈如何以不同的方式解决相同的问题。第一部分:渲染,围绕每个 UI 框架都必须回答的一个问题展开。

UI 框架经常被比作功能目录:这个框架支持热重载,那个框架提供原生外观和体验,第三个框架共享代码。记住这些功能并不等同于理解它们。更深层次的问题始终如一:当状态改变时,框架敢于重做多少屏幕内容?

每一种渲染架构都是对这个问题的答案,而每个答案都会在某些方面提升效率,并在其他方面付出代价。UI 渲染没有免费的午餐。

本系列文章是我对三大移动技术栈的个人研究——追踪它们的渲染管线,并比较它们对相同问题的解答。追踪一次状态变更在机制中的运行过程,这三种架构可以归结为三种策略:

Android Views: 原地修改树状结构。

Flutter: 快速重建所有内容,进行差异比较和修补。

Compose: 订阅状态,仅重新运行读取器。

本文将追踪一次状态变更——点击后计数器递增——在每种架构中的运行过程:哪些工作被执行,哪些工作被跳过,以及每种设计旨在避免哪些故障。

第一部分 — Android Views:可变树状结构

Flutter 考虑了同步问题,并做出了一个激进的赌注:如果保持可变树真实是困难的部分,那就停止变异。每次从状态描述整个 UI,并让框架找到差异。

这个赌注之所以有效,是因为 Flutter 将 UI 分成了三棵树

小部件 — 不可变的描述,自由重建。从设计上来说,创建它们的成本很低;它们是配置,而不是机械。 元素 - 幸存下来的持久中间层会重建并保持状态。 渲染对象 — 用于测量、布局和绘制的昂贵机器。

相同的计数器,Flutter 风格:

1
2
3
4
5
6
7
8
9
10
11
12
class _CounterScreenState extends State<CounterScreen> {
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return Column(children: [      Text('$count'),
      ElevatedButton(
        onPressed: () => setState(() => count++),
        child: const Text('+'),
      ),
    ]);
  }
}

没有任何视图可以进入。 “build”方法是同步:状态和 UI 不能不一致,因为 UI 每次都会根据状态重新计算。

我们的水龙头调用“setState”。该框架为该小部件的子树重新运行“build()”,生成一个新的小部件树 - 包括新的“Text(‘1’)”描述。然后元素树将新的与旧的进行比较:相同的运行时类型和键 → 保留现有的 Element 和 RenderObject,只需更新它们即可;不同→拆除并重新创建。这个一位数的变化结束了它的旅程,作为对现有渲染对象的一个​​小更新,就像视图世界一样——但没有人必须记住去做它。

这可以防止失败: 状态 UI 漂移。每次更改时屏幕都会从模型中重新派生,因此它不能默默地不同意它。而且,由于 Flutter 通过自己的引擎(现在是 Impeller,历史上是 Skia)自行绘制每个像素,因此同一棵树在 Android、iOS 及其他平台上的渲染效果相同——通过完全拥有画布解决了碎片问题。

它的回报是:乐观的工作。无论是否发生任何变化,重建都会发生,并且差异的存在是为了在事后扔掉废物。在预算紧张的情况下——长清单、低端设备——无纪律的重建会变得很糟糕,而社区的工具箱(“const”构造函数、细粒度的“BlocBuilder”放置、键)在很大程度上是一个手动缩小爆炸半径的工具箱。拥有每一个像素还意味着重新实现操作系统免费提供的功能:文本编辑、滚动物理、可访问性桥梁——永远追逐平台的发展。

第三部分 — 撰写:订阅和补丁

跟踪所有三台机器的一位数变化,并将策略压缩到一个表中:

无字幕图像

当突变很少且层次结构稳定时,Views 是正确的机器 - 并且它仍然是每个 Android 开发人员必须了解的世界,因为这两种新机器都可以解决其弱点。

当产品要求像素相同的多平台 UI,并且你的团队对重建范围有严格要求时,Flutter 是合适的机器。

当你希望框架承担真实性负担和效率负担,并且愿意学习它悄悄要求你遵守的稳定性合同时,Compose 是合适的机器。

生产中的大多数渲染性能问题不是由于选择了错误的机器而引起的,而是由于使用一台机器而精神上却生活在另一台机器中——像 Flutter 中的 Views 开发人员一样变异,或者像 Compose 中的 Flutter 开发人员一样提升状态读取。这些框架的不同之处并不在于它们可以做什么,而在于它们默默地期望你做什么。

本系列的下一篇:状态管理 —“LiveData”、“Bloc”、“StateFlow”,以及为什么每个生态系统从不同方向汇聚到流上。

本系列是作者对 Android Native、KMP 和 Flutter 的个人研究——它们在幕后如何工作、它们的不同之处以及它们各自对你的期望。

Comments