Flutter Tuning--In-depth exploration of the reasons and solutions for interface Rebuild caused by MediaQuery | JD Cloud Technical Team

foreword

We can MediaQuery.of(context)get some device and system related information through methods, such as the height of the status bar, whether it is currently in dark mode, etc. It is quite convenient to use, but we must also pay attention to possible page rebuild problems. This article will introduce a typical example, and go deep into the source code to discuss the cause of the rebuild, and finally introduce several ways to avoid the rebuild.

typical example

Take the courier checking scenario in the courier app as an example. The homepage uses MediaQuery.of(context).padding.topthe height of the status bar, and the user clicks the "Check courier" button to jump to the courier checking interface. On the courier checking interface, the user can enter the tracking number to perform query operations.

99ee34767149efcdb4c81258d84649c76ec7d0b5.jpeg
When the build method on the home page is called, it will output the logs we added in advance. We found that when the keyboard of the check express interface pops up, the build method of the home page is called multiple times:

1c71b25e3294787a554ff654302a1950b05f1e2c.png

The build code of the main interface is as follows:

0e60e8a0008a952db4058f2f6c7c7f4d2156d1bf.png

Source Code Exploration

Since it is because the main interface is used in the build method MediaQuery.of(context), which leads to the rebuild operation when the keyboard pops up/hides, let's look at the next MediaQueryclass first.

MediaQuery

ca93e1de11acadcdacc1be8bf1621c53ab4d4e67.png

It inherits from InheritedWidgetand does not have a rewriting createElementmethod itself. From the perspective of the flutter three trees, the corresponding one Elementis InheritedElement. There are two attributes, data and child, we can get some device/system related attributes from data.

There are also two more important methods:

fromWindow(key : Key, child : Widget)

5b724d4ff9ae1364473ce47a81a5c0c4fcd247ef.png

This method returns the object directly _MediaQueryFromWindow, which will be described in detail later.

of(context : BuildContext)

50.png

The method calls dependOnInheritedWidgetOfExactType, and then we analyze the calling process behind it in detail.

MediaQuery.of(context) call process

The input parameter is context, the main interface in this example is StatelessWidget, so here contextis StatelessElement. The overall calling process is as follows:

845592be3d798d7f664f343d1c3bc2e28b2ed114.png

dependOnInheritedWidgetOfExactType

0921532a03e10a237cce55d11b688cac76e3744e.png

_inheritedWidgetsQuery whether there is MediaQuerya type from the list InheritedElement. From the perspective of the three trees, it is to search upwards from the current node to find the nearest MediaQuerycontrol. If found, call dependOnInheritedElementthe method (under normal circumstances, it must be found, and will be described in detail below).

dependOnInheritedElement

3475047fddc5392b520ed244eaf9bde411a21349.png

This method is responsible for saving the found InheritedElement(that is, MediaQuerythe corresponding Element) and calling InheritedElement#updateDependenciesthe method.

updateDependencies

fc0db47c49a1f82bde4797e316087c40bda77d35.png

setDependencies

a33b8a6c17284ec860c808104a5e9b5796a3e247.png

StatelessElementThe last two methods are very simple, and their function is to store the corresponding ones of the homepage in MediaQuerythe corresponding ones InheritedElement#_dependents.

After studying MediaQuery.of(context)the principle behind it, we can know: by calling the of method, the main interface corresponds to the binding relationship established, Elementand the reference of the main interface is stored correspondingly .MediaQueryMediaQueryInheritedElementElement

Rebuild starting point

When introducing dependOnInheritedWidgetOfExactTypethe method, we mentioned: Searching from the current node to the parent node, under normal circumstances, it is sure to find MediaQuerythe control. This is because WidgetsAppa root is automatically created for us in MediaQuery.

In mainthe method, whatever is used CupertinoAppor MaterialAppwill be created internally at the end WidgetsApp. Let's look directly at _WidgetsAppState#builda code snippet in the method:

b99a11825cca09b3db11d7d08c0f2f7e97b1b83a.png

will be checked first widget.useInheritedMediaQuery, this property defaults to false. If you don't set the property when you create MaterialApp/ , or set the property to null, but can't find it , then the method will be called here.CupertinoAppuseInheritedMediaQueryMediaQueryDataMediaQuery.fromWindow

When introduced above MediaQuery#fromWindow, we knew it would create _MediaQueryFromWindowcontrols.

628215f6ff6f55a7e4253fd82aec42af96564435.png

_MediaQueryFromWindowThere are not many codes, and all the codes related to this article are posted. You can take a look at them yourself. The code is shown in the figure above.

buildThe control is created in the method MediaQuery, and the method is implemented didChangeMetrics. When the phone rotates and the keyboard pops up/hides, this method will be called, and it will didChangeMetricsbe called internally setSate, causing buildthe method to be called again.

Through the principle of flutter's three trees, we can know that the above-mentioned "build method is called again" involves the MediaQueryFromWindowcorresponding Elementmethod updateChild. Let's briefly look at updateChildthe internal processing rules:

a33b8a6c17284ec860c808104a5e9b5796a3e247.png

For MediaQueryFromWindow, a new MediaQuery Widget is created every time. According to the source code of Element#updateChild (not the focus of this article, we will not analyze its source code in detail), it will eventually call the update method of the Element corresponding to MediaQuery.

After a series of jumps, the following two core methods will eventually be called:

beb27e10f74c988d10e0de4fda450f52aec77be7.png

The method introduced above MediaQuery.of(context)will eventually put the input parameters Contextinto _dependentsthe variable, and this will be traversed here map, and each method will be called Context, didChangeDependeciesand didChangeDependeciesthis will Contextbe set to a dirty state. When the next frame comes, it will be redrawn and this Contextmethod buildwill be called.

So, the case is solved, and the reason why the express homepage will be rebuilt when the keyboard pops up/hides is found!

The overall rebuild call process is as follows. If you are interested, you can combine this call flow chart to see the source code:

bf648f2c2399def55a9fdb1a20260ef2fe858394.png

Ways to avoid rebuild

After studying the source code, the solution becomes very simple.

  • The custom useInheritedMediaQueryattribute is true, and the outermost layer MediaQueryis WidgetsAppused for creation MediaQuery, instead of using _MediaQueryFromWindowthe control that monitors the size change of the application.

f048696ba22681d3cefab511748656b38a3d1098.png

  • Avoid using the method on the page MediaQuery.of(context), you can use the corresponding alternative method, for example, in this example, you can use the following code instead, pay attention to the unit conversion.

17ebf14ed1e437106cd05b5c17f2da2aeb815213.png

  • If you must use MediaQuery.of(context)the method, you can use Builderthe control package, and the input parameters of the of method can be passed in here Builder, contextso that the rebuild is only Builderthe widget subtree under the control package.

5e9bafc27455cbba7c69653d1052f73c1ed71fa5.png

Summarize

When the app interface becomes more complex, we have to consider optimizing interface performance. The examples introduced in this article are very common in development. If you don’t understand the mechanism of MediaQuery.of, it may cause a large number of interfaces that use this method to redraw, resulting in page freezes and frame rate drops. We analyzed the source code logic behind it in detail and introduced the solution, hoping to provide some help for your tuning work.

Author: JD Logistics Shen Mingliang

Source: JD Cloud Developer Community

Guess you like

Origin blog.csdn.net/JDDTechTalk/article/details/130924888