Flutter 高性能滚动列表优化实践

阅读时长 8 分钟读完

Flutter 是一款跨平台的 UI 框架,能够快速构建出高品质、高性能的应用程序。当应用程序中需要大量展示条目时,通常会用到滚动列表(也称为滑动容器、ListView)来优化性能。但是,如果不进行优化,大量的数据渲染将会占用大量的内存,导致应用程序的性能下降甚至崩溃。因此,本文将围绕 Flutter 高性能滚动列表的优化实践展开,通过深入分析实现方案、性能优化技巧,展现在开发时如何减小渲染成本,提高用户体验。

ListView

在 Flutter 中,滚动列表通常用 ListView 来实现。在 ListView 中,Flutter 可以很容易地实现两种类型的列表:

普通列表

普通列表显示的是一些水平或垂直的文本或者图片等等。大部分 Flutter 应用程序里常常需要用这种类型的滚动列表。我们可以通过以下代码来实现:

-- -------------------- ---- -------
---------
  --------- ---------
    ---------
      -------- ------------------
      ------ --------------
      --------- ---------- -----
    --
    ---------
      -------- ------------------
      ------ --------------
      --------- ---------- -----
    --
    ---------
      -------- ------------------
      ------ --------------
      --------- ---------- -----
    --
  --
--

GridView

GridView 是另外一种常用的滑动列表,它可以显示一些布置在二维网格中的列表。GridView 有许多不同的展示方式,如以下两个例子:

-- -------------------- ---- -------
---------------
  --------------- --
  --------- ---------
    ----------
      ------- ---
      ------ -----------------------------------
    --
    ----------
      ------- ---
      ------ -----------------------------------
    --
    -----
  --
--
-- -------------------- ---- -------
-----------------
  ------------- ------------------------------------------
      --------------- --
      ---------------- ----
      ----------------- ----
  --
  ------------ ------------- -------- --- ------ -
    ------ ----------
      ------- ---
      ------ ---------------------------------- - ---------
    --
  --
  ---------- --
--

列表的性能问题

如果列表中的数据量较小,那么不用过多考虑性能问题。但是如果列表中的数据量很大,那么这时候就需要考虑性能问题了。这篇文章主要介绍以下针对滚动列表性能的优化措施:

  1. 池化(缓存)机制
  2. 视域(ViewPort)机制
  3. 数据预拉取(Pre-Fetching)机制

池化(缓存)机制

池化机制就是为了复用滑动列表子项的内存,降低Flutter的内存占用,减少Flutter的垃圾回收,提高滑动效率。Flutter通过子项复用的方式来实现缓存数据、控件的优化。针对可变长度的列表Flutter通过“滚动池”(ScrollPools)的方式来缓存列表子项。这样的设计能够减少Flutter对于子项内存的申请和释放,可以降低程序卡顿的概率,提高Flutter应用的性能。我们可以通过以下代码来实现:

ListView.builder 告诉 Flutter 想要显示 1000 项,并设置显示每项是 Text('Index: $index') 。这时候 Flutter 会根据当前的滑动位置动态地缓存一小部分选项,而不是渲染所有的 1000 项。当向上或向下滑动时,Flutter 会自动将已经渲染完成的选项从缓存池中取出来重用,然后使用新的数据更新它们。 如此一来,ListView.builder 就能够具备更高的性能和更低的内存消耗。

视域(Viewport)机制

在滚动列表中,视域指的是当前可见的部分。对于想要大量展示列表的应用来说,保证视域内的内容能够进行快速的绘制,非常关键。因此,Flutter 提供了一种名为 SliverList 和 SliverGrid 的机制,可以将列表控件可见的部分作为一个片段来渲染。当向上或向下滚动该列表时,Flutter 会回收那些超出视域范围的区域,这样一来,一只滑动指令就能够高效的完成,保证了应用程序的流畅。

使用 Sliver 来构建滑动列表,是一种高度灵活、可定制且可扩展的方式。Flutter 的滚动列表架构基于可组合的 Sliver 布局。Sliver 是对需要组合在一起的不同部分的列表进行建模的一种方式,每个不同部分都独立的被构建、更新和绘制。Sliver 布局使得列表可以很容易的进行扩展,如添加头部、分割线等等。Sliver 布局也让我们可以覆盖默认的 Flutter 列表样式,并完全控制滚动列表的所有部分。

ListView(以及其他所有滚动列表组件)都是由多个 Sliver 组成的组合。最常用的基础 Sliver 组件有五种:

  1. SliverAppBar:带着滑动出现和收起效果的应用栏。
  2. SliverList:在线性方向上排列子项的视图。
  3. SliverFixedExtentList:每一行子项拥有确定高度的基于 SliverList 的实现。
  4. SliverGrid:将子项排成二位的视图。
  5. SliverPadding:在视图周围添加一些装饰。

数据预拉取(Pre-Fetching)机制

预拉取可以增加你的组件的渲染效率。当你的应用程序中滑动容器快要滚到底时,预拉取机制可以先加载部分数据,减少视图的输入延迟。这个机制同样可以帮助用户在快速滚动容器时获得更好的体验,并且减少了 Flutter 应用程序的内存占用和性能消耗。

Flutter 滑动容器的预拉取机制依赖于 ScrollController,一个控制滑动容器滚动位置的对象。当某个/一些/所有子项进入/准备进入可见区域时(ScrollOffset),Flutter 会触发 ScrollController 的回调函数。借此回调函数,我们可以知道容器的滑动位置,以及预拉取进行到哪一行。这样子就可以及时加载需要展示的数据,同时确保用户在下一次滚动时依然可以像往常一样流畅的操作。

可以使用以下代码来实现数据预拉取机制:

-- -------------------- ---- -------
----- ---------------- ----------- - -------------------

---------
---- ----------- -
  ------------------
  -----------------------------------
-

---- ----------- -
  ----- ---------- - ----------------------------
  -- --------
  ----- ------ - ------------------------------------ - ---
  -- ----------- -- ------- -
      -- -------
      ----------- -
        ----------------------------------- -------------- ---- ------------- - -----
      ---
  -
-

-----

-----------------
  ----------- ------------
  ---------- --------------
  ------------ ------------- -------- --- ------ -
      -----
  --
--

总结

尽管 Flutter 在大量列表项目的渲染上表现非常优异,但是我们仍然需要遵循最佳实践来确保最佳绩效。广泛的消费层应用程序使用普通的 ListView 是没有问题的,但在某些使用情形下,特别是需要大量元素渐进地加载或需要提供视差效果的应用,使用可定制的 Sliver 布局就更加合适。我们在 Flutter 中可以通过下面的方式来优化许多常见的应用程序滚动列表展示。

  • 充分利用池化(缓存)机制,尽量避免因创建过多的新对象而导致 Flutter 的内存消耗过大,影响用户体验。
  • 遵循视域(Viewport)机制,保证视域内(可见区域内)的内容能够准确高效地渲染,降低因性能问题而导致的页面卡顿。
  • 按照实际需求设置合理的数据预拉取(Pre-Fetching)机制,缩短等待时间,快速响应用户的操作。

总的来说,只有遵循最佳实践、紧跟技术潮流、灵活多变,才能在 Flutter 应用的性能优化方面做得更好,满足不同用户的需求,减少因性能问题而导致的流失率,提高用户留存率。本文尝试通过深入分析实现方案和性能优化技巧,帮助读者更好地理解和掌握 Flutter 高性能滚动列表的真谛,为 Flutter 应用的性能优化提供参考和指导。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64c6f65310032fedd3902f9b

纠错
反馈