Flutter best practices for Improve Performance

1. Use Widgets over Functions

Don’t use it like this

Widget _buildFooterWidget() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text('This is the footer '),
);
}.
class FooterWidget extends StatelessWidget {
@override

Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text('This is the footer '),
);
}
}
Widget functionWidget({ Widget child}) {
return Container(child: child);
}
functionWidget(
child : functionWidget()
)
class ClassWidget extends StatelessWidget {
final Widget child;
const ClassWidget({Key key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: child,
);
}
}
new ClassWidget(
child : new ClassWidget(),
)
Container
Container
ClassWidget
Container
ClassWidget
Container

Why that matters

By using functions to split your widget tree into multiple widgets, you expose yourself to bugs and miss on some performance optimizations.

  • Avoid rebuilding all the widgets repetitively
  • And it would be a good idea to add const.
  • User itemExtent in ListView for long lists.
  • Avoid rebuilding unnecessary widgets inside animatedBuilder
body: AnimatedBuilder(
animation: _controller,
builder: (_, child) => Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(360 * _controller.value * (pi / 180.0)),
child: CounterWidget(
counter: counter,
),),
),
body: AnimatedBuilder(
animation: _controller,
child : CounterWidget(
counter: counter,
),
builder: (_, child) => Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(360 * _controller.value * (pi / 180.0)),
child: child),
),

2. Use const where possible

class CustomWidget extends StatelessWidget {
const CustomWidget();
@override
Widget build(BuildContext context) {
...
}
}
  • When building your widgets, or using flutter widgets. this helps flutter to rebuild only widgets that should be updated. The widget will not change when setState calls. It will prevent the widget to rebuild.
  • You can save CPU cycles and use them with a const constructor.

3. Use nil instead const Container()

// good
text != null ? Text(text) : const Container()
// Better
text != null ? Text(text) : const SizedBox()
// BEST
text != null ? Text(text) : nil
or
if (text != null) Text(text)

4. Accelerate Flutter performance with Keys

// FROM
return value
? const SizedBox()
: const Placeholder(),
// TO
return value
? const SizedBox(key: ValueKey('SizedBox'))
: const Placeholder(key: ValueKey('Placeholder')),
----------------------------------------------// FROM
final inner = SizedBox();
return value ? SizedBox(child: inner) : inner,
// TO
final global = GlobalKey();
final inner = SizedBox(key: global);
return value ? SizedBox(child: inner) : inner,

5. Optimize memory when using image ListView

ListView.builder(
...
addAutomaticKeepAlives: false (true by default)
addRepaintBoundaries: false (true by default)
);

6. Follow Dart style

Identifiers: Identifiers come in three flavors in Dart

  • UpperCamelCase names capitalize the first letter of each word, including the first.
  • lowerCamelCase names capitalize the first letter of each word, except the first which is always lowercase, even if it’s an acronym.
  • lowercase_with_underscores names use only lowercase letters, even for acronyms, and separate words with _.

DO name types using UpperCamelCase.

Classes, enum types, typedefs, and type parameters should capitalize the first letter of each word (including the first word), and use no separators.

good
class SliderMenu { ... }
class HttpRequest { ... }
typedef Predicate<T> = bool Function(T value);
const foo = Foo();
@foo
class C { ... }

DO name libraries, packages, directories, and source files using

Good
library peg_parser.source_scanner;
import 'file_system.dart';
import 'slider_menu.dart';
Bad
library pegparser.SourceScanner;
import 'file-system.dart';
import 'SliderMenu.dart';

7. Use MediaQuery/LayoutBuilder only when needed

8. Make use of async/await instead of then function.

9. Efficiently use operators

var car = van == null ? bus : audi;         // Old pattern
var car = audi ?? bus; // New pattern
var car = van == null ? null : audi.bus; // Old pattern
var car = audi?.bus; // New pattern
(item as Car).name = 'Mustang'; // Old pattern
if (item is Car) item.name = 'Mustang'; // New pattern

10. Make use of interpolation techniques

// Inappropriatevar discountText = 'Hello, ' + name + '! You have won a brand new ' + brand.name + 'voucher! Please enter your email to redeem. The offer expires within ' + timeRemaining.toString() ' minutes.';// Appropriatevar discountText = 'Hello, $name! You have won a brand new ${brand.name} voucher! Please enter your email to redeem. The offer expires within ${timeRemaining} minutes.';

11. Use for/while instead of foreach/map

You can check the comparison of loops in this article

12. Precache your images and icons

precacheImage(AssetImage(imagePath), context);For SVGs
you need flutter_svg package.
precachePicture(
ExactAssetPicture(
SvgPicture.svgStringDecoderBuilder,iconPath),context,
);

13. Use SKSL Warmup

flutter run --profile --cache-sksl --purge-persistent-cacheflutter build apk --cache-sksl --purge-persistent-cache

14. Consider using the RepaintBoundary widget

Flutter widgets are associated to RenderObjects. A RenderObject has a method called paint which is used to perform painting. However, the paint method can be invoked even if the associated widget instances do not change. That’s because Flutter may perform repaint to other RenderObjects in the same Layer if one of them is marked as dirty. When a RenderObject needs to be repainted via RenderObject.markNeedsPaint, it tells its nearest ancestor to repaint. The ancestor does the same thing to its ancestor, possibly until the root RenderObject. When a RenderObject’s paint method is triggered, all of its descendant RenderObjects in the same layer will be repainted.

15. Use builder named constructors if possible

For example
Listview → Listview.builder

16. Proper disposal of data

Unnecessary RAM usage kills inside the app silently. So don’t forget to dispose your data

16. Set cacheHeight and cacheWidth values to images

  • You can reduce memory usage in this way

17. Don’t use referencing for your List and Map

  • Don’t use it like
List a = [1,2,3,4];
List b;
b = a;
a.remove(1);
print(a); // [2,3,4]
print(b); // [2,3,4]
  • Use it like
List a = [1,2,3,4];
List b;
b = jsonDecode(jsonEncode(a));
a.remove(1);
print(a); // [2,3,4]
print(b); // [1,2,3,4]

Happy Hunting!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
InFicial Infotech

InFicial Infotech

163 Followers

We are a team of talented I.T professionals who can help you to convert your ideas into reality.