Flutter app: How to improve its performance?

FLUTTER APP

How to create an app, you ask? Today, ArrowHiTech will introduce a ‘brand new’ mobile framework: Flutter. Developed by Google, it seems to be a very powerful framework. Because of its new publication, there’s lots of room for improvements. What can you do to better the Flutter app?

Before diving into our main concern, first, let’s have a look at the basic information.

What is Flutter?

Flutter is an open-source UI and software development kit. It was created by Google in May, 2017 (v0.0.6).

At first, it was actually revealed as ‘Sky’ in 2015, and could run on Android. Up until December 2018, Flutter 1.0 was released and marked the first stable Flutter version.

The latest version at the time of writing this article is 1.17.5 and released on July 2, 2020. Up to this day, Flutter fully supports app for multiple operating systems: Android, iOS, Linux, Mac, Windows and Google Fuchsia

Although Flutter is relatively new, many agencies worldwide are using it to offer services to big names in different industries:

  • Singsys (Singapore): KPMG, Deloitte, E&Y
  • Mindinventory (India): Panasonic, Everly
  • GeekyAnts (India): Google
  • NetGuru (Poland): Volkswagen, Damac
  • Intelivita (UK): Microsoft, ITV
  • Bacancy (India): Disney, Mercedes, Redbull, 3M
  • and many more…

Why should you go for Flutter app?

a. Custom Widgets kit

Thanks to Google, the material design can easily create such powerful UI experiences. With a native app, a smooth and graceful App experience is 100% possible.

b. High Performance

Because Flutter does not need JavaScript, the speed is much faster than others.

c. Programming Language

Flutter uses Dart – a client-optimized language for fast apps also created by Google. Moreover, Dart helps build mobile, desktop, server as well as web applications. Compared to JavaScript, Dart is much faster because of its wonderful syntax. As a result, this is a unique strength of Flutter to its competition.

Dart: what is it and why Flutter uses Dart?

d. Third Parties

Because Flutter is compatible with both iOS and Android, it reduces Third Parties.

e. Hot Reload

Hot reload in Flutter is fast and necessary for popular products or apps namely Facebook and Instagram.

f. UI

UI in Flutter is very expressive and flexible. For this reason, it grants huge access to a wide range of custom designs.

g. API

Flutter’s API is very consistent. Furthermore, it offers unlimited possibilities. For example, a button can be used as a screen or a full page as a button via animation and transformation.

And now we get to the main point!

Dos and Don’ts to improve Flutter app performance

flutter do and dont
Flutter app dos and don’ts

To NOT DO

1. Split widgets into methods

This is a common mistake if you have a large layout. Usually, it will waste CPU cycles when you refresh the whole widget. Below is 2 examples to show what is the correct option:

wrong example

class MyHomePage extends StatelessWidget {
  Widget _buildHeaderWidget() {
    final size = 40.0;
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: CircleAvatar(
        backgroundColor: Colors.grey[700],
        child: FlutterLogo(
          size: size,
        ),
        radius: size,
      ),
    );
  }

  Widget _buildMainWidget(BuildContext context) {
    return Expanded(
      child: Container(
        color: Colors.grey[700],
        child: Center(
          child: Text(
            'Hello Flutter',
            style: Theme.of(context).textTheme.display1,
          ),
        ),
      ),
    );
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(15.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            _buildHeaderWidget(),
            _buildMainWidget(context),
            _buildFooterWidget(),
          ],
        ),
      ),
    );
  }
}

correct example

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(15.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            HeaderWidget(),
            MainWidget(),
            FooterWidget(),
          ],
        ),
      ),
    );
  }
}

class HeaderWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final size = 40.0;
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: CircleAvatar(
        backgroundColor: Colors.grey[700],
        child: FlutterLogo(
          size: size,
        ),
        radius: size,
      ),
    );
  }
}

class MainWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Container(
        color: Colors.grey[700],
        child: Center(
          child: Text(
            'Hello Flutter',
            style: Theme.of(context).textTheme.display1,
          ),
        ),
      ),
    );
  }
}

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

2. Rebuild widgets repetitively

Using ‘ValueNotifier’ or ‘ChangeNotifier’ in the same examples below is one of the best ways.

class _MyHomePageState extends State<MyHomePage> {
  final _colorNotifier = ValueNotifier<Color>(Colors.grey);
  Random _random = new Random();

  void _onPressed() {
    int randomNumber = _random.nextInt(30);
    _colorNotifier.value =
        Colors.primaries[randomNumber % Colors.primaries.length];
  }

  @override
  void dispose() {
    _colorNotifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    print('building `MyHomePage`');
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _onPressed,
        child: Icon(Icons.colorize),
      ),
      body: Stack(
        children: [
          Positioned.fill(
            child: BackgroundWidget(),
          ),
          Center(
            child: ValueListenableBuilder(
              valueListenable: _colorNotifier,
              builder: (_, value, __) => Container(
                height: 150,
                width: 150,
                color: value,
              ),
            ),
          ),
        ],
      ),
    );
  }
}
//------ ChangeNotifier class ----//
class MyColorNotifier extends ChangeNotifier {
  Color myColor = Colors.grey;
  Random _random = new Random();

  void changeColor() {
    int randomNumber = _random.nextInt(30);
    myColor = Colors.primaries[randomNumber % Colors.primaries.length];
    notifyListeners();
  }
}
//------ State class ----//

class _MyHomePageState extends State<MyHomePage> {
  final _colorNotifier = MyColorNotifier();

  void _onPressed() {
    _colorNotifier.changeColor();
  }

  @override
  void dispose() {
    _colorNotifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    print('building `MyHomePage`');
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _onPressed,
        child: Icon(Icons.colorize),
      ),
      body: Stack(
        children: [
          Positioned.fill(
            child: BackgroundWidget(),
          ),
          Center(
            child: AnimatedBuilder(
              animation: _colorNotifier,
              builder: (_, __) => Container(
                height: 150,
                width: 150,
                color: _colorNotifier.myColor,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

3. Rebuild excessive widgets inside AnimatedBuilder

This is pretty uncommon and fairly simple to fix. Thus, we highly recommend hiring experts like ArrowHiTech. Unless you have some technical base, here is the official link to AnimatedBuilder. Feel free to check them out!

4. Use Opacity in an animation

Instead, you should go for one of these two alternatives

  • FadeTransition
class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  int counter = 0;

  void _onPressed() {
    setState(() {
      counter++;
    });
    _controller.forward(from: 0.0);
  }

  @override
  void initState() {
    _controller = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 600));
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _controller.reverse();
      }
    });
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _onPressed,
        splashColor: Colors.red,
        child: Icon(Icons.slow_motion_video),
      ),
      body: FadeTransition(
        opacity: Tween(begin: 1.0, end: 0.0).animate(_controller),
        child: CounterWidget(
          counter: counter,
        ),
      ),
    );
  }
}
  • AnimatedOpacity
const duration = const Duration(milliseconds: 600);

class _MyHomePageState extends State<MyHomePage> {
  int counter = 0;
  double opacity = 1.0;

  void _onPressed() async {
    counter++;
    setState(() {
      opacity = 0.0;
    });
    await Future.delayed(duration);
    setState(() {
      opacity = 1.0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _onPressed,
        splashColor: Colors.red,
        child: Icon(Icons.slow_motion_video),
      ),
      body: AnimatedOpacity(
        opacity: opacity,
        duration: duration,
        child: CounterWidget(
          counter: counter,
        ),
      ),
    );
  }
}

To DO

Here are the key ideas to consider if you want to upgrade Flutter app.

1. Use const widgets (if possible)

Until when we have 2 prints statements like follow, one is in the main while one is in the background widget

flutter: building `MyHomePage`
flutter: building `BackgroundWidget`

Then, if you use ‘Const’, the code will be:’

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _onPressed() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    print('building `MyHomePage`');
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _onPressed,
        child: Icon(Icons.colorize),
      ),
      body: Stack(
        children: [
          Positioned.fill(
            child: const BackgroundWidget(),
          ),
          Center(
              child: Text(
            _counter.toString(),
            style: Theme.of(context).textTheme.display4.apply(
                  color: Colors.white,
                  fontWeightDelta: 2,
                ),
          )),
        ],
      ),
    );
  }
}

class BackgroundWidget extends StatelessWidget {
  const BackgroundWidget();

  @override
  Widget build(BuildContext context) {
    print('building `BackgroundWidget`');
    return Image.network(
      'https://cdn.pixabay.com/photo/2017/08/30/01/05/milky-way-2695569_960_720.jpg',
      fit: BoxFit.cover,
    );
  }
}

2. Use ‘itemExtent’ in ListView (if you have long lists)

class MyHomePage extends StatelessWidget {
  final widgets = List.generate(
    10000,
    (index) => Container(
      color: Colors.primaries[index % Colors.primaries.length],
      child: ListTile(
        title: Text('Index: $index'),
      ),
    ),
  );

  final _scrollController = ScrollController();

  void _onPressed() async {
    _scrollController.jumpTo(
      _scrollController.position.maxScrollExtent,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _onPressed,
        splashColor: Colors.red,
        child: Icon(Icons.slow_motion_video),
      ),
      body: ListView(
        controller: _scrollController,
        children: widgets,
        itemExtent: 200,
      ),
    );
  }
}

Looking for help? Contact AHT right now!

Founded in 2007, ArrowHiTech has been working in the IT outsourcing field for more than 12 years. With over 10,000 projects completed for thousands of clients, we are confident that our experience and skilled developers can solve any problems for you.

arrowhitech

Being one of leading Flutter app development company, ArrowHiTech has gained expertise over this emerging technology recently introduced by Google! You can check out our portfolio or Flutter App Development and Mobile App Development as there are many more to see!

Wrap Up

So, today we have learned about Flutter and useful ways to improve Flutter app performance. We hope that you have seen lots of new ideas today to adapt into your app!

As always, AHT wishes you the best of good luck and success! For more questions, feel free to Contact Form

Tags

Share