1

Can Flutter be fast compared to other hybrid platforms? The answer is yes, but with that in mind, let's take a look at some amazing performance and optimization practices.

original

https://inficial.medium.com/flutter-best-practices-for-improve-performance-7e21e14efebb

refer to

text

1. Use Widgets instead of functions

don't use it like this

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

use it like this

 class FooterWidget extends StatelessWidget {
  @override

   Widget build(BuildContext context) {
  return Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text('This is the footer '),
         );
      }
}

If a function could do the same thing, Flutter wouldn't have a StatelessWidget.

Similarly, it is mainly for public widgets, which can be reused. It doesn't matter that a private function can only be used once — though it's still good to be aware of this behavior.

There is an important difference between using functions instead of classes, and that is: the framework doesn't know about functions, but can see classes.

Consider the following "widget" function:

 Widget functionWidget({ Widget child}) {
    return Container(child: child);
}

Use like this:

 functionWidget(
    child : functionWidget()
)

And it's equivalent:

 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,
              );
  }
}

Use like this:

 new ClassWidget(
  child : new ClassWidget(),
)

On paper, both seem to do the same thing: create 2 containers, one nested within the other. But the reality is slightly different.

For functions, the resulting widgets tree looks like this:

 Container
  Container

For classes, the widgets tree is:

 ClassWidget
  Container
    ClassWidget
      Container

This is important because it changes the behavior of the framework when updating widgets.

why this matters

By using a function to split the widget tree into widgets, you are exposing yourself to bugs and missing out on some performance optimizations.

Using functions is not guaranteed to have bugs, but using classes guarantees that you will not encounter these problems.
the issues:

Here are some interactive examples on Dartpad that you can run yourself to better understand these issues:

In general, using functions on classes to reuse widgets is considered a bad practice for these reasons. You can, but it might bite you in the future.

  • Avoid rebuilding all widgets repeatedly
  • Also, adding const is a good idea.
  • User item range for a ListView long list.

Specifying itemExtent is more efficient than letting the sub-scroll mechanism determine its extent, because the scroll mechanism can take advantage of the sub-scroll mechanism's prior knowledge to save work, such as when the scroll position changes drastically.

  • Avoid rebuilding unnecessary widgets in animatedBuilder

don't use it like this

 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,
               ),),
),

This will rebuild the CounterWidget widgets when the animation occurs. If you put the log in the counterWidget's build method, you can see that it prints a log every time the animation occurs.

Use it like this.

 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),
),

We use the subproperties provided by AnimatedBuilder, which allow us to cache widgets to reuse them in animations. We do this because the widget doesn't change, the only thing it does is rotate, but for that we have Transform widgets.

More information:

https://blog.codemagic.io/how-to-improve-the-performance-of-your-flutter-app./#dont-split-your-widgets-into-methods

2. Use const whenever possible

 class CustomWidget extends StatelessWidget {
   const CustomWidget(); @override
  Widget build(BuildContext context) {
    ...
  }
}
  • When building widgets, or using flutter widgets. This helps flutter only rebuild widgets that should be updated. The widgets do not change when setState is called. It will prevent widgets from rebuilding.
  • You can save CPU cycles and use them with const constructors.

3. Use nil instead of 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)

Add a simple widget to the widgets tree with minimal performance impact when you don't want to display anything.

https://pub.dev/packages/nil

4. Use keys to improve Flutter performance

 // 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,

This provides better performance by using the flutter of keys to better identify widgets.

5. Optimize memory when using image ListView

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

ListView can't kill it's children because they are not visible on the screen. If children have high-resolution images, it will consume a lot of memory.

Doing these options wrong can result in using more GPU and CPU work, but it can fix our memory issues and you'll get a very high performance view with no apparent issues.

Flutter Memory Optimization Series

Almost everything in Flutter is optimized and enhanced by default, as you probably already know, thanks to the Flutter team at ..

https://medium.com/flutter-community/flutter-memory-optimization-series-8c4a73f3ea81

6. Follow the Dart style

Identifiers: : There are three styles of identifiers

  • UpperCamelCase names capitalize the first letter of each word, including the first.
  • lowerCamelCase capitalizes the first letter of every word, except the first letter is always lowercase, even if it's an acronym.
  • lowercase*with_underscores Names use only lowercase letters, even for acronyms, and words that use \_.

Use UpperCamelCase to name types

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

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

Use the following named libraries, packages, directories, and source files

 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';

For more styles, check out Dart styles:

An amazingly important part of good code is good style. Consistent naming, ordering and formatting helps code..

https://dart.dev/guides/language/effective-dart/style

For more rules, check out the Dart connector:

https://dart-lang.github.io/linter/lints/index.html

7. Use MediaQuery/LayoutBuilder only when needed

8. Use async/await instead of then functions

9. Use operators effectively

 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. Using String Template Interpolation

 // Inappropriate

var 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.';

// Appropriate

var 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

Comparing Dart's coils — which is the fastest?

Dart, the language in which Flutter apps are written, has many different loops that can loop through a list or run some ..

https://itnext.io/comparing-darts-loops-which-is-the-fastest-731a03ad42a2

12. Display your images and icons precisely

 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-cache
flutter build apk --cache-sksl --purge-persistent-cache

If an application has clean animations on the first run, and then becomes smooth for the same animations, it is likely due to delays in shader compilation.

14. Consider RepaintBoundary widgets

Flutter widgets are associated with render objects. Render objects have a method called paint that performs painting. However, the paint method can be called even if the associated widget instance does not change. This is because Flutter may perform a repaint on other render objects in the same layer if one of them is marked dirty. When a render object needs to be repainted via RenderObject.markneedspaint, it tells its nearest ancestor to repaint. Ancestors do the same for their ancestors, possibly up to the root RenderObject. When a render object's paint method is triggered, all its child render objects in the same layer will be repainted.

In some cases, when a render object needs to be repainted, other render objects in the same layer do not need to be repainted because what they render remains the same. In other words, it would be better if we could only repaint certain render objects. Using RepaintBoundary is useful to limit the spread of markneedspain and paintChild through the render tree. RepaintBoundary decouples ancestor renderers from descendant renderers. Therefore, only subtrees whose content has changed can be redrawn. Using RepaintBoundary can significantly improve the performance of your application, especially if subtrees that don't need to be repainted require a lot of repainting work.

15. Use named constructors if possible

 // 例如

Listview → Listview.builder

16. Appropriate processing of data

Unnecessary memory usage kills data silently inside the app, so don't forget to dispose of your data

Some packages provide autorelease support for their classes

If you don't know what a Flutter hook is and how to use it

Remove all kinds of boilerplate code with Flutter hooks

Don't you think, it's time to close StatefulWidget and use flutter hook to remove boilerplate code

https://iisprey.medium.com/get-rid-of-all-kind-of-boilerplate-code-with-flutter-hooks-2e17eea06ca0

set cacheHeight and cacheWidth to image

You can reduce memory usage this way

17. Don't use references in List Maps

don't use it like this

 List a = [1,2,3,4];
List b;
b = a;
a.remove(1);
print(a);  // [2,3,4]
print(b);  // [2,3,4]

For this reason, whenever you try to call any method of list a, list b is automatically called.

For example a.remove (some) ; will also remove the item from list b;

use it like this

 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]

end

I hope this gave you some insight to improve the performance of your Flutter app. Happy coding!


© Cat Brother

订阅号


独立开发者_猫哥
669 声望129 粉丝