202 lines
4.3 KiB
Markdown
202 lines
4.3 KiB
Markdown
---
|
|
name: advanced-performance
|
|
description: Flutter performance optimization - const constructors, keys, widget rebuilds, and performance best practices
|
|
---
|
|
|
|
# Performance Optimization
|
|
|
|
Optimize Flutter app performance by following best practices.
|
|
|
|
## Const Constructors
|
|
|
|
Use `const` constructors to avoid unnecessary rebuilds.
|
|
|
|
```dart
|
|
// ✅ Good - const constructor
|
|
const Text('Hello')
|
|
|
|
// ❌ Bad - new instance on every build
|
|
Text('Hello')
|
|
|
|
// Use const widgets when values don't change
|
|
class MyWidget extends StatelessWidget {
|
|
const MyWidget({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const Column(
|
|
children: [
|
|
Text('Static text'),
|
|
Icon(Icons.star),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Keys
|
|
|
|
Use keys to preserve state when widgets move in the tree.
|
|
|
|
```dart
|
|
// Use ValueKey for list items
|
|
ListView.builder(
|
|
itemBuilder: (context, index) => ListTile(
|
|
key: ValueKey(items[index].id),
|
|
title: Text(items[index].name),
|
|
),
|
|
)
|
|
|
|
// Use GlobalKey to access state from outside
|
|
final _formKey = GlobalKey<FormState>();
|
|
Form(key: _formKey, ...)
|
|
```
|
|
|
|
## Widget Rebuilds
|
|
|
|
Minimize widget rebuilds by splitting widgets.
|
|
|
|
```dart
|
|
// ❌ Bad - entire widget rebuilds on counter change
|
|
class BadWidget extends StatefulWidget {
|
|
@override
|
|
State<BadWidget> createState() => _BadWidgetState();
|
|
}
|
|
|
|
class _BadWidgetState extends State<BadWidget> {
|
|
int _counter = 0;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
children: [
|
|
ExpensiveWidget(), // Rebuilds unnecessarily
|
|
Text('Counter: $_counter'),
|
|
ElevatedButton(
|
|
onPressed: () => setState(() => _counter++),
|
|
child: const Text('Increment'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
// ✅ Good - split widgets to minimize rebuilds
|
|
class GoodWidget extends StatefulWidget {
|
|
@override
|
|
State<GoodWidget> createState() => _GoodWidgetState();
|
|
}
|
|
|
|
class _GoodWidgetState extends State<GoodWidget> {
|
|
int _counter = 0;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
children: [
|
|
const ExpensiveWidget(), // const prevents rebuild
|
|
CounterDisplay(counter: _counter),
|
|
ElevatedButton(
|
|
onPressed: () => setState(() => _counter++),
|
|
child: const Text('Increment'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
## ListView Optimization
|
|
|
|
Use `ListView.builder` for efficient list rendering.
|
|
|
|
```dart
|
|
// ✅ Good - builds items on demand
|
|
ListView.builder(
|
|
itemCount: items.length,
|
|
itemBuilder: (context, index) => ListTile(
|
|
title: Text(items[index].name),
|
|
),
|
|
)
|
|
|
|
// ❌ Bad - builds all items at once
|
|
ListView(
|
|
children: items.map((item) => ListTile(
|
|
title: Text(item.name),
|
|
)).toList(),
|
|
)
|
|
```
|
|
|
|
## Image Optimization
|
|
|
|
Optimize image loading and caching.
|
|
|
|
```dart
|
|
// Use cached_network_image package
|
|
CachedNetworkImage(
|
|
imageUrl: 'https://example.com/image.jpg',
|
|
placeholder: (context, url) => CircularProgressIndicator(),
|
|
errorWidget: (context, url, error) => Icon(Icons.error),
|
|
)
|
|
|
|
// Precache images
|
|
precacheImage(AssetImage('assets/image.png'), context);
|
|
```
|
|
|
|
## Build Methods
|
|
|
|
Keep build methods lightweight.
|
|
|
|
```dart
|
|
// ❌ Bad - heavy computation in build
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final expensiveData = computeExpensiveData(); // Don't do this
|
|
return Text(expensiveData);
|
|
}
|
|
|
|
// ✅ Good - compute in initState or use FutureBuilder
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FutureBuilder(
|
|
future: computeExpensiveData(),
|
|
builder: (context, snapshot) {
|
|
if (!snapshot.hasData) return CircularProgressIndicator();
|
|
return Text(snapshot.data);
|
|
},
|
|
);
|
|
}
|
|
```
|
|
|
|
## RepaintBoundary
|
|
|
|
Isolate repaints to specific widgets.
|
|
|
|
```dart
|
|
RepaintBoundary(
|
|
child: AnimatedContainer(
|
|
duration: Duration(seconds: 1),
|
|
width: _width,
|
|
height: _height,
|
|
color: Colors.blue,
|
|
),
|
|
)
|
|
```
|
|
|
|
## Key Points
|
|
|
|
- Use `const` constructors whenever possible
|
|
- Use keys to preserve state in lists
|
|
- Split widgets to minimize rebuilds
|
|
- Use `ListView.builder` for long lists
|
|
- Optimize image loading and caching
|
|
- Keep build methods lightweight
|
|
- Use `RepaintBoundary` to isolate repaints
|
|
- Profile with Flutter DevTools to identify bottlenecks
|
|
|
|
<!--
|
|
Source references:
|
|
- https://docs.flutter.dev/perf/best-practices
|
|
- https://docs.flutter.dev/perf/rendering
|
|
-->
|