MST

星途 面试题库

面试题:Flutter自定义StatefulWidget的性能优化

假设你已经构建了一个复杂的自定义Flutter StatefulWidget,在频繁更新状态的情况下,描述一些你会采取的性能优化策略,例如如何避免不必要的重绘,以及如何合理利用StatefulWidget的shouldRebuild方法。
22.7万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试
  1. 避免不必要的重绘
    • 使用const和final
      • 在构建Widget树时,尽量使用constfinal修饰Widget。const Widgets在编译时就确定,不会在运行时改变,Flutter可以更高效地复用它们。例如,const Text('固定文本'),这样的文本Widget不会因为父Widget的状态变化而重绘。
      • final变量也是不可变的,对于一些不会改变的对象,使用final声明有助于性能提升。
    • 局部构建
      • 只在真正需要更新的部分进行构建。例如,如果一个复杂的页面有一个列表和一些固定的标题,当列表数据更新时,只重建列表部分,而不是整个页面。可以使用AnimatedBuilderIndexedStack等Widget来实现局部构建。例如,使用AnimatedBuilder来包裹需要根据动画状态更新的部分:
AnimatedBuilder(
  animation: animationController,
  builder: (context, child) {
    return Container(
      // 这里只构建与动画相关的部分
    );
  },
  child: child,
);
  • 使用AutomaticKeepAliveClientMixin
    • 对于那些需要保持状态且不需要频繁重建的Widget,例如分页中的各个页面,可以使用AutomaticKeepAliveClientMixin。这样,当这些Widget被移出屏幕后,不会被销毁重建,下次再显示时可以保持原来的状态,避免了不必要的重绘。例如:
class MyPage extends StatefulWidget {
  @override
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container();
  }
}
  1. 合理利用shouldRebuild方法
    • 对比新旧状态
      • shouldRebuild方法中,通过对比新旧状态来判断是否真的需要重建。例如,如果StatefulWidget的状态是一个包含多个属性的类,可以只对比那些真正影响Widget外观的属性。
class MyComplexWidget extends StatefulWidget {
  MyComplexWidget({Key key}) : super(key: key);

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

class _MyComplexWidgetState extends State<MyComplexWidget> {
  MyData _data;

  @override
  void initState() {
    _data = MyData();
    super.initState();
  }

  @override
  bool shouldRebuild(_MyComplexWidgetState oldState) {
    // 只对比需要关注的属性
    return oldState._data.someImportantProperty != _data.someImportantProperty;
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

class MyData {
  int someImportantProperty;
}
  • 避免复杂计算
    • shouldRebuild方法中的逻辑应该尽量简单高效。因为这个方法会在每次状态变化时被调用,如果其中包含复杂的计算,可能会影响性能。例如,不要在shouldRebuild中进行网络请求或复杂的数据库查询等操作。