Flutter App性能优化关注点

参考:官方文档

控制build()消耗

  • 避免在build方法中进行重复和高消耗的工作,因为build方法可能会被频繁的调用(当父组件、祖先组件rebuild时,当前组件的build也会被调用)。
  • 尝试将大组件拆分为多个小组件。当一个组件的setState被调用时,它的所有子孙组件也会rebuild。因此如果只是某一个子组件发生了变化,那就尽量只调用该子组件的setState,而不要去调用其父组件或祖先组件的setState。
  • 缓存没有变化的子树(If a subtree does not change, cache the widget that represents that subtree and re-use it each time it can be used)。参考下面AnimatedBuilder的做法。
  • 尽可能使用const组件(这样做与缓存一个组件并复用它是等价的)。(Use const widgets where possible. (This is equivalent to caching a widget and re-using it.))
  • 尽量不要改变组件树的结构或者组件树中组件的类型。它们会造成整个组件树的重新布局和渲染。

避免使用代价昂贵的效果

减少使用Opacity组件

直接绘制带有透明度的图片或颜色,比在组件外层套一个Opacity组件要更高效。下面例子展示了如何直接绘制一个带有50%透明度的图片:

Image.network(
  'https://raw.githubusercontent.com/flutter/blend_mode_destination.jpeg',
  color: Color.fromRGBO(255, 255, 255, 0.5),
  colorBlendMode: BlendMode.modulate
)

或者使用AnimatedOpacity、FadeInImage组件替代。

减少使用Clip组件

大部分圆角效果可以通过borderRadius来实现,并不是非要用Clip组件。

列表懒加载

使用ListView.builder(当item滚入屏幕时才创建item):

final List<String> entries = <String>['A', 'B', 'C'];
final List<int> colorCodes = <int>[600, 500, 100];

ListView.builder(
  padding: const EdgeInsets.all(8),
  itemCount: entries.length,
  itemBuilder: (BuildContext context, int index) {
    return Container(
      height: 50,
      color: Colors.amber[colorCodes[index]],
      child: Center(child: Text('Entry ${entries[index]}')),
    );
  }
);

而不是ListView-children(会立刻创建所有的item):

ListView(
  padding: const EdgeInsets.all(8),
  children: <Widget>[
    Container(
      height: 50,
      color: Colors.amber[600],
      child: const Center(child: Text('Entry A')),
    ),
    Container(
      height: 50,
      color: Colors.amber[500],
      child: const Center(child: Text('Entry B')),
    ),
    Container(
      height: 50,
      color: Colors.amber[100],
      child: const Center(child: Text('Entry C')),
    ),
  ],
)

16ms

Since there are two separate threads for building and rendering, you have 16ms for building, and 16ms for rendering on a 60Hz display.

在Android Studio中提供了性能分析工具“Flutter Performance”,可以查看每一帧的绘制时间和build()方法的调用次数等信息。

使用AnimatedBuilder

如果你的build方法中包含一个不依赖于动画的子树,那么更高效的做法是只build此子树一次,而不是在动画的每一帧都build它。

通过child参数将预构建(pre-built)的子树传递给AnimatedBuilder,然后AnimatedBuilder就会在渲染每一帧动画时将此子树传递给builder方法(从而避免了在渲染每一帧动画时都要去构建子树):

class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key}) : super(key: key);

  @override
  _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget>
    with TickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 10),
      vsync: this,
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      child: Container(
        width: 200.0,
        height: 200.0,
        color: Colors.green,
        child: const Center(
          child: Text('Whee!'),
        ),
      ),
      // 每个动画帧会调用此builder方法
      builder: (BuildContext context, Widget child) {
        return Transform.rotate(
          angle: _controller.value * 2.0 * math.pi,
          child: child,
        );
      },
    );
  }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值