Improving Rendering Performance in Flutter App
By: Shivanchal Pandey
Tags: Mobile App Development, App Performance, Flutter, Rendering, App Development

In order to maintain app performance, we make every possible effort but any app’s performance relies on two main things which are time and space. The space-related issue is explained in my previous blog where I have explained how to reduce app size and make your app performant.

Rendering is the key factor that provides smoothness to the app and it depends on the fps.

You must be thinking about how no of frames per second can help in the app performance and you must have heard a lot about 60 fps and 16 milliseconds barries. So for information Human mind reacts according to the visual signals sent by the eyes and there is no concept of frames in this regard but the concept of motion has its own effect in this regard. By displaying images at a faster speed you can trick the mind into perceiving motion and here the concept of fps(Frames per second)comes into the effect. It means a concept of motion is a kind of hack of mind.

It needs a minimum of 10–12 frames per second when the human mind starts perceiving motion but it does not look smooth, 24 frames per second allow the human eye to see fluid motion but in movies and videos it takes at least 60 frames per second where a human mind easily feels a smooth motion with fluency.

So the formula would look like

1000ms / 60 frames = 16.666 ms/frame

It means you need to replace every frame in 16.66 milliseconds to do your work computing, input, network, and rendering if you are not able to do this you need to find out where your app lacks and where it needs improvement.

Identifying Performance

In order to identify the performance issue, you just need to open tools here you can identify the no of times the widget is rebuilding and where you need to correct or need to make some changes to your code.

Improve Rendering performance

If the performance is the issue rendering is the factor that comes first in the list we need to deal with, but flutter’s Skia engine takes care of it. Generally, if we are dealing with performance issues there are some common pitfalls

Rebuilding more of the UI in every frame

So try not to write code for the whole screen in a single Stateful Widget that may cause unnecessary UI building, you need to split code into smaller widgets and smaller build functions.

Building a large list of children directly and operating things up higher in the tree using setState().

So setState() affects apps rendering performance more than anything so instead of calling high up on the tree try to call it on the specific part of the subtree.

How to Improve Performance?

In order to improve build performance, there are some steps which we need to improve and some of them are

Controlling build()

Repetitive code and heavy work should be avoided in the build() method so the build() method can be invoked frequently when widgets are rebuilt.

Apply Effects when needed

Applying effects are always expensive because it causes or responsible to create saveLayer() behind the scenes.

Why is savelayer expensive? Calling saveLayer() allocates an offscreen buffer. Drawing content into the offscreen buffer might trigger render target switches that are particularly slow in older GPUs.

Some rules need to be followed

Use the Opacity widget if it is necessary if you using it for a single image there are various options to doing so because For example, Container(color: Color.fromRGBO(255, 0, 0, 0.5)) is much faster than Opacity(opacity: 0.5, child: Container(color: Colors.red)) .

Directly drawing an Image or Color with opacity is faster than using Opacity on top of them because Opacity could apply the opacity to a group of widgets and therefore a costly offscreen buffer will be used. Drawing content into the offscreen buffer may also trigger render target switches and such switching is particularly slow in older GPUs.

Clipping doesn’t call saveLayer() (unless explicitly requested with Clip.antiAliasWithSaveLayer ) so these operations aren’t as expensive as Opacity, but clipping is still costly, so use with caution. By default, clipping is disabled ( Clip.none ), so you must explicitly enable it when needed.

Some widgets are costly because they call saveLayer() and are potentially costly

Shader Mask

color filter

chip

text

There are also some other widgets you may call instead such as to provide fading in an image we can call FadeInImage because it applies gradual opacity using GPU’S fragment shader. In order to provide a rounded corner, we should prefer a border-radius instead of clipping.

Rendering Grids and Lists lazily can help to build up the potion which is going to be seen firstly.

Manage Shader Compilation Jank

If any animation seems janky during the first run but after it works fine maybe this is an issue of shader compilation jank.

More deeply and technically, Shader is a set of code that runs on a GPU( Graphics processing unit). A smooth frame needs to be drawn within 16 milliseconds for a 60 fps display but during the compiling shader takes more time than it should take. it could be nearly a few hundred milliseconds and it causes tens of frames to be missed and drops the fps from 60 to 6.

How to sort it out?

As a Solution for this after the release of Flutter 1.20, Flutter provides command-line tools for developers and by this developers can collect shaders that might be needed for the end-users in the Skia Shader Language format. Once SkSL shader will be packaged into the app then it will automatically be pre-compiled when the end-user opens the app.

There are few commands to perform the action

Run the app with --cache-sksl turned on to capture shaders in SkSL:

flutter run --profile --cache-sksl

If the same app has been previously run without --cache-sksl , then the --purge-persistent-cache the flag may be needed:

flutter run --profile --cache-sksl --purge-persistent-cache

This flag removes older non-SkSL shader caches that could interfere with SkSL shader capturing. It also purges the SkSL shaders so use it only on the first --cache-sksl run.

Build the app with SkSL warm-up using the following, as appropriate:

Android

flutter build apk — bundle-sksl-path flutter_01.sksl.json

Ios

flutter build ios --bundle-sksl-path flutter_01.sksl.json

Conclusion

These are some techniques to improve rendering performance that may help to make the app performant. Sometimes animations, growing list, some widgets (generally call saveLayer()) make an app janky and more rendering so in order to maintain these things we must make focus on the points mentioned above.

Thanks for reading this article if you find anything that could be improved please let me know, I would love to improve.💙

If this article has helped you a bit and found interesting please clap!👏