Flutter 列表性能的一套“长期安全写法”



子玥酱 (掘金 / 知乎 / CSDN / 简书 同名)

大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩‍💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。

我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案,

在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。

技术方向: 前端 / 跨端 / 小程序 / 移动端工程化 内容平台: 掘金、知乎、CSDN、简书 创作特点: 实战导向、源码拆解、少空谈多落地 **文章状态:**长期稳定更新,大量原创输出

我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在"API 怎么用",而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。

子玥酱 · 前端成长记录官 ✨

👋 如果你正在做前端,或准备长期走前端这条路

📚 关注我,第一时间获取前端行业趋势与实践总结

🎁 可领取 11 类前端进阶学习资源 (工程化 / 框架 / 跨端 / 面试 / 架构)

💡 一起把技术学"明白",也用"到位"

持续写作,持续进阶。

愿我们都能在代码和生活里,走得更稳一点 🌱

文章目录

大多数 Flutter 列表性能问题,不是"写错了",而是写得太随意了

它们在 Demo 里没问题、在首版也没问题、在数据量小的时候更没问题,但一旦:

  • 页面常驻
  • 状态变复杂
  • 列表变长
  • 需求开始叠加

问题一定会出现。

这套"安全写法"要解决什么问题

我们先明确目标,不是为了"更快",而是为了:

  • rebuild 范围可预测
  • 滚动成本稳定
  • 状态位置清晰
  • 后期改需求不崩盘

总结:

让列表的性能,和业务复杂度"线性增长",而不是指数爆炸。

列表容器不承载业务状态

永远不要这样写

dart 复制代码
class ListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final model = context.watch<ListModel>();

    return ListView.builder(
      itemCount: model.items.length,
      itemBuilder: ...
    );
  }
}

问题不在 ListView,而在这句:

dart 复制代码
context.watch<ListModel>()

这等于在告诉 Flutter:

"整个列表,依赖整个业务模型。"

长期安全写法

dart 复制代码
class ListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final count = context.select<ListModel, int>(
      (m) => m.items.length,
    );

    return ListView.builder(
      itemCount: count,
      itemBuilder: (context, index) {
        return ItemTile(index: index);
      },
    );
  }
}

列表容器只关心结构,不关心内容。

item 是 rebuild 的最小战斗单位

Flutter 列表的"安全边界",是 item,而不是列表。

Item 必须满足三点

  1. 足够小
  2. 足够纯
  3. 状态明确

推荐的 Item 写法

dart 复制代码
class ItemTile extends StatelessWidget {
  final int index;
  const ItemTile({required this.index});

  @override
  Widget build(BuildContext context) {
    final item = context.select<ListModel, Item>(
      (m) => m.items[index],
    );

    return ListTile(
      title: Text(item.title),
      subtitle: Text(item.subtitle),
    );
  }
}

rebuild 边界非常明确:

只有这个 item 的数据变了,它才 rebuild。

能 Stateless,就不要 Stateful

这是 Flutter 列表里一个长期收益极高的习惯

Stateful item 的隐性成本

  • 状态容易被 keepAlive
  • Element 复用时更复杂
  • 错位问题更隐蔽

很多"诡异 Bug",都来自 Stateful item。

如果你真的需要局部状态

比如:

  • 是否展开
  • 是否选中
  • 动画进度

明确声明它的生命周期

dart 复制代码
class ExpandableItem extends StatefulWidget {
  final Item item;
  const ExpandableItem({required this.item});

  @override
  State<ExpandableItem> createState() => _ExpandableItemState();
}

class _ExpandableItemState extends State<ExpandableItem> {
  bool expanded = false;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListTile(
          title: Text(widget.item.title),
          onTap: () {
            setState(() => expanded = !expanded);
          },
        ),
        if (expanded) Text(widget.item.detail),
      ],
    );
  }
}

并且默认不 keepAlive

key 不是可选项

在长期维护的列表中:

没有 key 的列表,迟早出事。

正确使用 key

dart 复制代码
return ItemTile(
  key: ValueKey(item.id),
  index: index,
);

不要用:

  • index
  • hashCode
  • runtimeType

key 的本质是身份,而不是位置。

列表 item 里不做"异步决策"

危险写法

dart 复制代码
itemBuilder: (context, index) {
  return FutureBuilder(
    future: fetchExtra(items[index].id),
    builder: ...
  );
}

问题不是 FutureBuilder,而是:

  • 滚动时会频繁触发
  • build 不再是纯函数
  • Debug 下性能极差

长期安全替代方案

  • 异步逻辑提前到 model
  • item 只展示状态
dart 复制代码
class Item {
  final String title;
  final String? extra;
}

页面复杂了,优先 Sliver

当你出现以下需求时:

  • Header + 列表
  • 吸顶
  • 多段列表
  • 页面常驻

不要犹豫,直接 Sliver。

推荐结构模板

dart 复制代码
CustomScrollView(
  slivers: [
    SliverToBoxAdapter(
      child: HeaderView(),
    ),
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return ItemTile(index: index);
        },
        childCount: count,
      ),
    ),
  ],
);

Sliver 的好处不是快,而是:

  • rebuild 传播路径短
  • 结构天然清晰
  • 后期加需求不翻车

keepAlive 是"高级权限"

AutomaticKeepAliveClientMixin

在列表里,永远是最后考虑的选项

问问自己三个问题

  1. 这个状态真的值得活着吗?
  2. 离开屏幕后还能复用吗?
  3. 内存上涨你能接受吗?

如果有一个答不上来:

不要 keepAlive。

"长期安全"的完整 Demo 结构

dart 复制代码
class ListModel extends ChangeNotifier {
  final List<Item> items = [];

  void updateItem(int index, Item newItem) {
    items[index] = newItem;
    notifyListeners();
  }
}
dart 复制代码
class ListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final count = context.select<ListModel, int>(
      (m) => m.items.length,
    );

    return CustomScrollView(
      slivers: [
        SliverToBoxAdapter(child: HeaderView()),
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (context, index) {
              return ItemTile(
                key: ValueKey(
                  context.read<ListModel>().items[index].id,
                ),
                index: index,
              );
            },
            childCount: count,
          ),
        ),
      ],
    );
  }
}

长期"安全"的原因

总结一下它解决了什么:

  • rebuild 边界清晰
  • item 粒度稳定
  • 滚动成本可控
  • 状态不扩散
  • Debug / Release 行为一致

总结

Flutter 列表性能,从来不是靠"技巧堆出来的"。

真正能活得久的列表,只有一个特征:

结构清楚,状态克制。

当你把这套写法变成肌肉记忆之后:

  • Debug 下你会更安心
  • 需求改动你会更从容
  • 性能问题会变成"可以推理的问题"
相关推荐
Ryuuuuko16 小时前
认知驱动的AI黑客:鸾鸟Agent如何让渗透测试拥有“人类专家”思维?
安全
行者9616 小时前
Flutter鸿蒙跨平台开发:实现高性能可拖拽排序列表组件
flutter·harmonyos·鸿蒙
行者9616 小时前
Flutter FloatingActionButton在OpenHarmony平台的深度适配与优化实践
flutter·harmonyos·鸿蒙
档案宝档案管理17 小时前
权限分级+加密存储+操作追溯,筑牢会计档案安全防线
大数据·网络·人工智能·安全·档案·档案管理
数据光子17 小时前
【YOLO数据集】国内交通信号检测
人工智能·python·安全·yolo·目标检测·目标跟踪
携欢17 小时前
portswigger靶场之修改序列化数据类型通关秘籍
android·前端·网络·安全
资生算法程序员_畅想家_剑魔17 小时前
Kotlin常见技术分享-01-相对于Java 的核心优势-空安全
java·安全·kotlin
上海云盾安全满满17 小时前
防火墙数据安全守护
安全·系统安全
世界尽头与你17 小时前
CVE-2024-43044_ Jenkins agent connections 文件读取漏洞
安全·网络安全·渗透测试·jenkins