Flutter---列表的优化

207 阅读4分钟

常用的两种列表组件

  • 标准的ListView构造函数适用于短列表,对于具有大量列表项的长列表,需要用ListView.builder构造函数来创建。

  • 与标准的 ListView 构造函数需要一次性创建所有列表项不同的是, ListView.builder 构造函数只在列表项从屏幕外滑入屏幕时才去创建列表项

ListView加载机制

Flutter中ListView采用懒加载机制。对于ListView里面的每一个item,并不会在build阶段全部进行构建。而是在layout阶段,根据屏幕当前的尺寸以及缓存区的范围,动态的构建每一个item

为什么会出现卡顿

  • 滑动列表的这个过程,其实是由一个个的画面组成,术语称为
  • 对于大部分人而言,当每秒的画面达到60,也就是俗称60FPS的时候,整个过程就是流畅的。而不及60FPS的时候,就会产生卡顿的感觉
  • 一秒 60 帧,也就意味着平均两帧之间的间隔为 16.7ms。如果超过 16.7ms,在观感上就会出现卡顿

哪些场景容易出现卡顿

  1. 首次进入,列表构建的时候
  2. 快速滑动,一帧内构建多个item
  3. 多个item使用setState进行更新加载

优化思路

一. 分帧上屏

卡顿的本质原因是在一帧内,模块的运行时间过长,这不光是ListView的问题,所有有复杂元素的页面都一样。以下两种方法建议同时使用:

1.1: 优化模块更新时间

导致模块卡顿的原因是多样性的,有可能是widget太复杂没有进行局部刷新,或者是UI isolate进行大量计算; 
因此推荐项目使用mvvm模式,将数据和布局分开,并且主要的是`notifyListeners`进行局部刷新

1.2: 分帧运行

不优化模块的情况下,对时间进行分片提升流畅度 也就是俗称的分帧运行;
此方法可使用Flutter 自带的ListView.builder组件;
该组件默认先加载可视区域的数据,并随着用户的滑动进行加载剩下的数据,已加载的数据则按照缓存机制进行缓存

二. 复用Element

对于ListView及其家族列表官方默认存在一个缓存范围为250.0的cacheExtent的缓存区;
最简单的做法是将cacheExtent的范围设置大一点,则缓存可复用的element会多一点

2.1 使用 builder构建列表

当你的列表元素是动态增长的时候(比如上拉加载更多),请不要直接用children 的方式,一直往children 的数组增加组件,那样会很糟糕。对于 ListView.builder 是按需构建列表元素,也就是只有那些可见得元素才会调用itemBuilder 构建元素,这样对于大列表而言性能开销自然会小很多。

2.2 禁用 addAutomaticKeepAlives

  • addAutomaticKeepAlives 特性默认是 true,意思是在列表元素不可见后可以保持元素的状态,从而在再次出现在屏幕的时候能够快速构建。

  • 这其实是一个拿空间换时间的方法,会造成一定程度得内存开销。可以设置为 false 关闭这一特性。

  • 缺点是滑动过快的时候可能会出现短暂的白屏(实际会很少发生)。

2.3 addRepaintBoundaries 特性

 addRepaintBoundaries 是将列表元素使用一个重绘边界(Repaint Boundary)包裹,从而使得滚动的时候可以避免重绘。而如果列表很容易绘制(列表元素布局比较简单的情况下)的时候,可以关闭这个特性来提高滚动的流畅度。

2.4 尽可能将不变的组件使用const修饰

使用const相当于将元素缓存起来实现共用,若列表中某些元素或者组件是不变的,可使用const修饰使它们能达到共用

2.5 使用itemExtent确定列表元素滚动方向的尺寸

对于很多列表,我们在滚动方向上的尺寸是提前可以根据 UI设计稿知道的,如果能够知道的话,那么使用 itemExtent 属性制定列表元素在滚动方向的尺寸,可以提升性能。这是因为,如果不指定的话,在滚动过程中,会需要推算每个元素在滚动方向的尺寸从而消耗计算资源

点击跳转原文