Flutter listview的复用与原生有什么区别

14 阅读3分钟

前言:

在实际开发中,我们常听到:“Flutter 没有复用”、“item 滑出又重建了”、“initState 怎么又调用了?”

那么:

  • Flutter 到底有没有“复用”?
  • ListView 渲染到底做了什么?
  • 如何优化 ListView 的滑动性能?

🏗️ 一、ListView 渲染整体架构图

ListView
 └── SliverList / SliverChildBuilderDelegate
      └── itemBuilder(index) ➜ Widget
             └── createElement()
                  └── mount() ➜ RenderObject ➜ Layer ➜ GPU

每个 item 构建并非无限保留,而是有生命周期的。


👀 二、你以为的“复用” VS 实际的渲染机制

❌ 误解:

“Flutter 和原生一样,滑动时 item 会被缓存、复用。”

✅ 真相:

Flutter 并没有复用 Widget 或 View 对象,而是做了更轻量级的结构销毁与重建,这是因为:

  • Flutter 是声明式 UI;
  • UI 结构是随时可以销毁 + 重建的;
  • ListView.builder 利用了Sliver + Delegate机制做到了:

只构建屏幕可见 + 边界预加载区域的 Widget,滑出后即销毁。


🔁 三、Flutter 怎么实现“复用”视觉效果的?

在滑动 ListView 时,我们有个直观感受是:

item 离开屏幕后,新的 item 快速出现,像是“复用”了前面的 item。

但 Flutter 并没有像 Android 那样有 ViewHolder 复用池。

那么它是怎么实现视觉上“复用”的呢?这里是关键逻辑:

✅ 1. 只构建“需要”的部分

  • ListView.builder 会只 build 屏幕可见区域 + cacheExtent 范围的 item;
  • 滑出视口范围的 Element 被标记为 inactive,下一帧就会被 unmount 销毁;
  • 这个“懒构建”机制避免了构建太多 widget 的消耗。

✅ 2. Widget diff 算法提升了构建效率

  • Flutter 的 Element.update() 方法会比较新旧 Widget:
if (widget.runtimeType == oldWidget.runtimeType &&
    widget.key == oldWidget.key) {
    // 复用旧的 Element 和 RenderObject,只更新内容
} else {
    // 销毁旧的 Element,重新构建
}
  • 所以 只要 key 和类型不变,Flutter 会走更新逻辑而不是销毁重建;
  • 这就像 Virtual DOM 的 diff,极大降低了性能开销。

✅ 3. RenderObject 尽量保持

  • 在 StatefulWidget 中,Element 的 _state._renderObject 会尽可能复用;
  • Flutter 框架避免在滑动过程中频繁创建新的 RenderObject;
  • GPU 层的 Layer、Picture 也通过缓存避免重复绘制。

⚠️ 四、Flutter 为什么不直接搞“View复用池”?

Flutter 是声明式 UI 框架,不适合维护复杂的对象池逻辑,原因是:

  • Widget 是轻量不可变的,没必要复用;
  • Element + RenderObject 已具备可控生命周期;
  • 显式“复用池”反而会让代码变复杂,违背 declarative UI 理念。

📐 五、与原生 Android / iOS 的对比

对比点Flutter ListViewAndroid RecyclerViewiOS UITableView
渲染方式Skia 图层 + 重建 UI 结构ViewHolder + 视图缓存池Cell + 重用队列
复用机制重建 Widget、State、Element缓存 ViewHolder 复用视图对象从复用队列中取出 Cell
控制粒度Flutter 管 Widget rebuild可精准控制每个 item 生命周期自动复用 Cell,提高效率
保持状态需手动 keepAlive 或 PageStorageView 持久存在,状态天然保留同上,Cell 未销毁可保状态
滚动性能构建轻、但频繁销毁构建滚动快,依赖 GC 控制内存滚动快,易出现“闪白”问题
状态保留默认销毁,需配置才保留默认保留默认保留

✅ 六、小结

方面Flutter ListView 的特点
✅ 优点构建简单,无需手动管理复用,配合 Builder 高效
⚠️ 注意默认 item 会销毁,不会自动保留状态
💡 提示想要类似原生复用效果,要配合 keepAlive 或 cacheExtent 等