遇没遇到性能问题,这些小技巧都值得关注。如果遇到了,他们可以帮助你发现和解决这些问题。如果还没有注意到,这些可以让你预防。也可以让解决这些问题的时候不至于手忙脚乱。
使用WidgetsBindingObserver来跟踪App的生命周期
使用WidgtesBindingObserver
来跟踪app的生命周期。使用这个widget可以捕捉到app的pause
、resume
等的回调,这样可以帮助开发者快速定位到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
,少用FutureBuilder
。StreamBuilder
会在收到流发出的事件之后才更新,也就是必要时才更新。这样会减少绘制的次数改善性能。
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
Wrap
比ListView
更加高效。因为它同样只绘制可见区域的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语言内置了Profile
和Release
两个模式来测试性能。Profile模式有详细的性能数据。Release模式则是为app的性能做了优化这样来发现和解决性能问题。
bash
flutter run --profile
Release模式:
bash
flutter run --release
最后
此文例子其实不够详细,建议也难免有些武断。但是,作为参考可以提供一些不同的思路。