提高Flutter App性能的几个小技巧

遇没遇到性能问题,这些小技巧都值得关注。如果遇到了,他们可以帮助你发现和解决这些问题。如果还没有注意到,这些可以让你预防。也可以让解决这些问题的时候不至于手忙脚乱。

使用WidgetsBindingObserver来跟踪App的生命周期

使用WidgtesBindingObserver来跟踪app的生命周期。使用这个widget可以捕捉到app的pauseresume等的回调,这样可以帮助开发者快速定位到app的性能瓶颈在哪里。

dart 复制代码
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }
  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    // Handle state changes here
  }
  //...
}

使用RepaintBoundary隔绝部分widget

使用RepaintBoundary widget可以把造成性能问题的那一部分widget和app的其他部分隔离。只要用这个widget把可能有性能问题的widget包起来就完成了隔离。

dart 复制代码
RepaintBoundary(
  child: MyExpensiveWidget(),
);

使用InheritedWidget传递数据

组成app的widget最终会形成一个树形结构。在传递数据的时候如果直接作为widget的参数传递不仅写起来麻烦也会造成不必要的重绘。使用InheritedWidget可以直接将数据从一个widget传到另外一个。

dart 复制代码
class MyInheritedWidget extends InheritedWidget {
  final int myData;

  MyInheritedWidget({
    Key key,
    @required this.myData,
    @required Widget child,
  }) : super(key: key, child: child);

  @override
  bool updateShouldNotify(MyInheritedWidget old) => myData != old.myData;

  static MyInheritedWidget of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }
}

多用StreamBuilder少用FutureBuilder

尽量多使用StreamBuilder,少用FutureBuilderStreamBuilder会在收到流发出的事件之后才更新,也就是必要时才更新。这样会减少绘制的次数改善性能。

dart 复制代码
StreamBuilder(
  stream: myStream,
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    if (snapshot.hasData) {
      return Text(snapshot.data);
    } else if (snapshot.hasError) {
      return Text(snapshot.error);
    }
    return CircularProgressIndicator();
  },
);

列表尽量使用CustomScrollView

尽量使用CustomScrollView,因为它只会回执可见区域的widget。

dart 复制代码
CustomScrollView(
  slivers: <Widget>[
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (BuildContext context, int index) {
          return MyListItem(data: myData[index]);
        },
        childCount: myData.length,
      ),
    ),
  ],
);

使用AnimationController控制动画

AnimationController可以控制动画的时间和进展,可以减少widget的重绘,改善性能。

dart 复制代码
class MyAnimationWidget extends StatefulWidget {
  @override
  _MyAnimationWidgetState createState() => _MyAnimationWidgetState();
}

class _MyAnimationWidgetState extends State<MyAnimationWidget>
    with SingleTickerProvider{
    AnimationController _controller;

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

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

    @override
    Widget build(BuildContext context) {
        return AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
        // Use _controller.value to control the animation
        return Transform.translate(
        offset: Offset(0, _controller.value * 100),
        child: child,
        );
        },
        child: MyChildWidget(),
        );
    }
}

尽量使用Wrap代替ListView

WrapListView更加高效。因为它同样只绘制可见区域的widget。

dart 复制代码
Wrap(
  children: myChildren.map((child) => MyChildWidget(child)).toList(),
);

使用CustomPainter绘制复杂图形

CustomPainter绘制更加高效,尤其是在绘制复杂的图形或者存在嵌套的时候。

dart 复制代码
class MyCustomPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // Draw complex graphics on the canvas
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

使用PerformanceOverlay实时呈现app的性能

PerformanceOverlay可以实时图形化的展现app的性能。

dart 复制代码
PerformanceOverlay(
  enabled: true,
  overlayRect: Rect.fromLTWH(0, 0, 200, 200),
  children: [
    // Your widgets
  ],
);

使用Dart内置的Profile和Release模式测试性能

dart语言内置了ProfileRelease两个模式来测试性能。Profile模式有详细的性能数据。Release模式则是为app的性能做了优化这样来发现和解决性能问题。

bash 复制代码
flutter run --profile

Release模式:

bash 复制代码
flutter run --release

最后

此文例子其实不够详细,建议也难免有些武断。但是,作为参考可以提供一些不同的思路。

原文地址:dev.to/yatendra200...

相关推荐
清风徐来QCQ14 分钟前
js中的模板字符串
开发语言·前端·javascript
成都渲染101云渲染666619 分钟前
Houdini+Blender高效渲染方案(高配算力+全渲染器兼容)
前端·系统架构
qq_2837200525 分钟前
MySQL技巧(四): EXPLAIN 关键参数详细解释
android·adb
SuperEugene35 分钟前
Vue3 + Element Plus 表格实战:批量操作、行内编辑、跨页选中逻辑统一|表单与表格规范篇
开发语言·前端·javascript
极梦网络无忧1 小时前
基于 Vite + Vue3 的组件自动注册功能
前端·javascript·vue.js
没有了遇见1 小时前
Android 架构之网络框架多域名配置<三>
android
Predestination王瀞潞1 小时前
5.4.3 通信->WWW万维网内容访问标准(W3C):WWW(World Wide Web) 协议架构(分层)
前端·网络·网络协议·架构·www
爱学习的程序媛1 小时前
【Web前端】优化Core Web Vitals提升用户体验
前端·ui·web·ux·用户体验
zabr1 小时前
花了 100+ 篇笔记,我整理出 了一套 AI Agent 工程完全指南
前端·后端·agent
软弹2 小时前
深入理解 React Ref 机制:useRef 与 forwardRef 的协作原理
前端·javascript·react.js