Flutter Pitfalls

Flutter Pitfalls
7 min read
27 December 2023

Author: Levkovskiy Ivan

Hello, everyone! My name is Ivan, and I work on mobile app development at APD. Today, we'll discuss the apparent and not-so-obvious challenges faced by Flutter developers. 

Flutter is a popular framework for building cross-platform mobile applications. It provides an extensive set of widgets and tools for developers, enabling the creation of visually appealing and high-performance apps. Flutter uses the Dart language for coding—a beautiful and straightforward programming language developed by Google. 

However, like any other technology, Flutter has its set of complexities and pitfalls that developers should be familiar with. In this article, we will explore some potential challenges and provide recommendations for effectively overcoming them.

Memory Management 

One of the key aspects of mobile app development is memory management. Flutter, like any other framework, requires developers to pay attention to how they manage memory to ensure optimal performance. 

When creating an application, every developer aims to make it as user-friendly, aesthetically pleasing, and fast as possible. One way to achieve this with minimal effort is by utilizing various specialized packages from pub.dev in the application. 

This can lead to an increase in the number of dependencies over time. Moreover, in later versions, new packages may be included in the project, performing the same functions as those integrated earlier. Each new package not only brings new features but also potential compatibility issues, as well as a disproportionately growing application size. 

Maintaining the hygiene of application dependencies is something every developer should strive for. Every quarter, we receive a fresh stable version of Flutter, providing an excellent opportunity to update and clean up all used dependencies. It is entirely possible that with a new update, a feature previously provided by a package can now be used "out of the box" in the framework itself, rendering the previously used package unnecessary.

Performance Issues 

The title might suggest that Flutter has inherent performance issues, but it's quite the opposite. Performance challenges often arise from incorrect implementation of certain functions by the developer.

  1. The Magic Word: 'const’

Flutter provides numerous performance optimization opportunities, guided by a well-configured linter (package for automatic code checking). One of these "magic pills" is the use of the 'const' prefix for widgets. Declaring a widget as constant accomplishes two things at once — optimizing the application rendering and improving memory usage. A constant widget is created only once and can be used as many times as needed. 

Unfortunately, using the 'const' prefix is not always possible in every case. There are situations where you need to execute code during the class constructor initialization or assign variables unrelated to constants. In such cases, the use of 'const' is not feasible, and developers are forced to abstain from its use.

  1. Defeating Parasitic Repaints

Let's imagine we have an animated widget that displays a loading state based on a CircularProgressIndicator, and we use it in the code somewhat like this: 

IsLoading ? CircullarProgressIndicator() : SomeWidgetWithData(), 

We expect that during the loading state, only the indicator widget itself, occupying a small part of the main screen, will be repainted, right? Let's check: 

void main() { 

debugRepaintRainbowEnabled = true; 

runApp(MyApp()); 

Enabling the debugRepaintRainbowEnabled property allows you to visually observe the boundaries of widget repaints on the screen.

In reality, the entire screen will be repainted. The animated widget affects the entire rendering layer of the screen, causing not only itself but also widgets higher up in the tree to be repainted

For such cases, Flutter has a remedy the RepaintBoundary widget. If you wrap the animated widget in a RepaintBoundary, all the repaints related to the animation will be handled by the framework on a separate layer, not affecting other widgets higher up in the tree. Unfortunately, everything comes at a cost RepaintBoundary consumes additional CPU and memory resources. Before using it, it is recommended to check the screen repaints by enabling the debugRepaintRainbowEnabled property.

Handling Exceptions and Errors 

This section applies not only to Flutter but also to code written in the Dart programming language. Occasionally, developers overlook handling exceptions that code may throw during runtime. I'll list some of the most commonly encountered ones:

  1. Working with Nullable Variables and the Bang Operator:

Periodically in our code, we use the so-called nullable variables variables that can be unassigned at a certain moment. Declaring them is simple - a question mark (?) is added to the type of the variable in the code, for example, int? a, String? b.

For ease of working with such variables, we can reference them, ignoring the null state using the Bang operator (!), for example:

a! + b!

However, this call is unsafe as it throws an exception when encountering null. In our practice, we strive to minimize the use of this operator. When forced to use it, we always add a null check before executing the associated code, for example:

If (a !=null && b != null) c = a!+ b!

Even better is to minimize the use of the (!) operator and use the (?) operator instead. For example:

c = (a ?? 0) + (b ?? 0);

  1. Asynchronous Errors

When working with external asynchronous functions, exceptions can occur at any point. Always consider this by enclosing your code in a try-catch block:

try { 

var result = await someAsyncOperation(); 

// Use the result 

} catch (e) { 

// Handle the asynchronous error

  1. State Errors 

These errors can occur in the most unexpected places. For example, you have a list, and you work with it seamlessly, like this:

final list = [1, 2, 3]; 

final result = list.first + list[2];

Everything goes smoothly until an empty list arrives instead of a populated one. Since you cannot access the first value of the list (list.first) or the third one (list[2]), the application will throw a State Error (red screen in debug mode), and the execution of dependent code on the screen will be interrupted. 

This is a tricky error that can only be detected by checking and testing the code. Always scrutinize the methods you call and read their documentation! 

A general piece of advice is, if you are unsure about the safety of the code, enclose it in a try-catch block. 

I hope the tips mentioned above prove useful for you. Flutter is a powerful and flexible framework that provides developers with a wide range of tools for creating high-quality applications. However, to achieve success, it's crucial to understand and use these tools correctly.

In case you have found a mistake in the text, please send a message to the author by selecting the mistake and pressing Ctrl-Enter.
Oleksandr 628
Joined: 1 year ago
Comments (2)
  1. Abdul Halim

    Author: Levkovskiy Ivan

    Hello, everyone! My name is Ivan, and I work on mobile app development at APD. Today, we'll discuss the apparent and not-so-obvious challenges faced by Flutter developers.

    1 month ago ·
    4
  2. Ibn Alhodi

    Честно говоря даже не знал, что день равноденствия где-то отмечают. Для меня это всегда чисто функцио

    1 month ago ·
    1
You must be logged in to comment.

Sign In / Sign Up