Performance is an essential element of any modern mobile application. Freezes and sipped frames affect the usability of a specific app and leave a bad user impression. A slow e-commerce application is as bad as an unusable stuttering game app. For a smooth user experience, a good app should maintain 60 FPS (frames per second) most of the time. This is the same as change frames every 16.66 milliseconds.
Most modern applications use a lot of visual elements, subjecting the device hardware to a heavy load. The best way to make it perform better is by improving the application’s code and build.
Surf has excellent experience developing Flutter apps, from e-commerce stores and mobile banking to corporate apps and streaming platforms. In this article, you will learn about the best practices to improve the performance of your Flutter application.
Flutter and Other Platforms
Flutter is a great cross-platform network developed by Google. It utilizes Dart coding language. Apart from being one of the famous cross-platform technologies available, it is also the most powerful performance-wise. Here is a detailed overview of its performance compared to other mobile app technologies.
Flutter vs. React Native performance
Several third-party examinations show that Flutter and React native offer a solid 60 FPS during regular scrolling. React Native uses a lot of memory and battery power of a specific device, creating a poor performance on the framework (this may drop to 7 FPS compared to 19 FPS for Flutter) when displaying heavy animations with scaling, rotations, and fade. Flutter is considered the best in this case.
Flutter vs. Ionic Performance
Xamarin vs. Flutter Performance
Both frameworks give a closely native performance. However, the performance of Xamaris will mostly depend on the kind of Xamarin framework in use. Suppose Xamarin.iOS and Xamarin. Android that has a more platform-specific code offers great performance, Xamarin. Forms that share a lot of code on various platforms will perform poorly.
A developer may also need a lot of user interface elements separately for Android and iOS with Xamarin. This means that the development of apps that require a heavy user interface will be much slower.
Flutter vs. Native Performance
In native platforms (apps written on Kotlin for Android and Swift for iOS), their performance is usually better than any cross-platform technology. The main reasons why the winner in the contests (Flutter vs. Swift performance of Flutter vs. Kotlin performance), the native platform will always win is because its code compilation is in a similar format to the native one of the device, and it utilizes almost half less the memory in virtually similar applications.
The performance of most Flutter applications is usually on the same level as native ones, thanks to the highly-optimized Skia rendering engine and AOT (ahead of time) compiler. Users won’t see a lot of difference.
How to Measure Flutter Performance
It is advisable to gauge performance in the profile mode using an actual device instead of an emulator. A low-end one is highly recommended. You can carry out performance testing in Flutter apps in multiple ways because the framework offers various tests and performance measurement options. Let’s look at the most popular ones below.
Using the performance widget is one way to carry out Flutter performance tests. This widget shows two graphs on top of the application. The first is the ‘GPU’graph at the top, which displays raster thread performance. This is the communication between the device’s GPU and the app’s layer tree.
The graph will show you how CPU resources are used despite being named GPU. The second is the ‘UI’ graph at the bottom which displays the UI thread, and it consists of a written code performed by Flutter’s framework.
The blue graph drops down to reveal a white background if you see a frame show for more than 16.6 milliseconds. You will also see a red vertical line, which usually means the app’s performance goes below 60 FPS. If this happens in the FPS graph, it is a sign that the visual components on the screen are so complicated to render in time.
If it occurs in the ‘UI’ graph, the Dart code is very expensive to perform in time. When you see a red bar in both graphs, start evaluating the UI thread for any arising issues.
You can launch the performance overlay in multiple ways, which include:
- The Flutter Inspector. Open the application in profile mode, launch DevTools, and go to the Inspector view. Here, you will find the Performance Overlay button.
- The command line. You have to use the command ‘flutter run-profile and the P key to turn on the performance widget.
The DevTools section has a performance view where you will find three tools to learn about the app.
Flutter Frames Chart
Has information about every frame, the work that happens during rendering from the raster (GPU) thread and the UI thread.
Timeline Events Chart
Keeps track of all the events in the app, including frame building, scene drawing, HTTP traffic, and many more.
Shows the amount of time each frame uses CPU and the trace method.
You can import or export data from the Performance view. We recommend having a look at Flutter documentation to learn more about the capabilities of the Performance view.
You can also measure the app’s performance using Flutter’s performance benchmark tests through integration testing. The evaluation shows metrics such as battery usage, startup time, and skipped frames (jank).
How to Optimize Flutter Performance
Avoid Expensive Build Method
The expensive and repetitive build() method uses a lot of CPU power. This may occur when you utilize a large widget containing a large build() function. You can divide it into smaller ones based on how they change and encapsulation. A perfect example is you can localize the setState() call to the subtree part (or child of a node) that needs changes in UI. It will rebuild all the descendent widgets of the tree if it’s called too high.
Use Const Widgets
Use const Constructor to keep the setState in a constant state and avoid excessive widget rebuilding.
Prefer Lazy Methods for Lists and Grids
Using Lazy Grids and Lazy Lists is ideal for large user interface elements. You will only render the part visible to the screen after launching the app.
Use Opacity When Necessary
The Opacity Widget rebuilds every frame using the widget, resulting in Flutter performance problems, especially when there is an animation. Applying opacity directly to images uses fewer resources, unlike the Opacity widget. You can also go for AnimatedOpacity, TransparentImage, FadeInTransition, or FadeInImage to improve your performance instead of using the Opacity widget.
Avoid Calls to Savelayer
You should do your best to avoid calling saveLayer(), which is more like taxing on the hardware. The widgets likely to prompt saveLayer() operation include: Chip (if disabledColorAlpha != 0xff); Text (if you use an overflowShader); ShaderMask and ColorFilter. You can make slight changes on the widget property of borderRadius to rectangle round corners instead of using a clipping rectangle to avoid calling saveLayer().
Build and Render in 16ms
You should examine which frames use more than 16 milliseconds to build and render if you notice an application skipping frames. There are multiple building and rendering threads, so you should target to build each frame in 8ms or less and render them in the same to get 16ms or something less in total.
There won’t be a major visual change for users if you render frames in less than 16ms. This might improve battery life and reduce the heating of the device.
Choose SizedBox Instead of Container
You should use the SizedBox widget to create whitespace or box for specified dimensions. This is less taxing on the system as compared to the Container widget.
Utilize Pre-Built Child Subtree with AnimatedBuilder
You should not place a child of a node that does not rely on animation in the builder function if you use the AnimatedBuilder widget. This is because it rebuilds the subtree on every inch of animation. The best thing is to create the subtree once and move it as a small parameter to the widget.
Avoid Using ListsView for Long Lists
You should create a list with ListView.builder constructor instead of Column() or ListView() if it’s not fully available at once on a screen. By following this, the constructor will render items on the screen as they are scrolled. This is better instead of creating them at once, which may impact the performance negatively.
Avoid Splitting Widgets into Methods
Splitting a large building method with different nesting levels into multiple methods is usually the first thought of many. This will force the rebuilding of all child widgets on Flutter every time the parent widget rebuilds despite some being completely static. You should divide complicated widgets into small StalessWidgets to avoid wasting CPU power in repetitive rebuilding.
Optimizing Flutter performance has the best reputation. The platform is famous among most developers because of how it offers close to native performance even in applications that have heavy visual elements. A perfect example is an app Surf developed for The Hole video streaming site.
Despite the massive doubts, Flutter handled the animations smoothly and offered responsive and smooth playback controls. You are always advised to stick to the best performance practices to minimize the risks of app errors, skipped frames, or stuttering to the minimum. It’s that simple! I am very hopeful our guide will help you meet your development goals.