4.3 KiB
4.3 KiB
| name | description |
|---|---|
| advanced-performance | 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.
// ✅ 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.
// 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.
// ❌ 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.
// ✅ 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.
// 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.
// ❌ 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.
RepaintBoundary(
child: AnimatedContainer(
duration: Duration(seconds: 1),
width: _width,
height: _height,
color: Colors.blue,
),
)
Key Points
- Use
constconstructors whenever possible - Use keys to preserve state in lists
- Split widgets to minimize rebuilds
- Use
ListView.builderfor long lists - Optimize image loading and caching
- Keep build methods lightweight
- Use
RepaintBoundaryto isolate repaints - Profile with Flutter DevTools to identify bottlenecks