• Stars
    star
    935
  • Rank 48,878 (Top 1.0 %)
  • Language
    Dart
  • License
    MIT License
  • Created over 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Components that optimize Flutter fluency.(Flutter 流畅度优化的通用方案,轻松解决卡顿问题)

Flutter fluency optimization component "Keframe"

image

Language: English | 中文简体

null-safe null-safe GitHub stars GitHub license

Optimize for lag caused by builds, such as page switches or rapid scrolling of complex lists, through frame-splitting rendering.

The following is Example(you can download it directly) running in VIVO X23 (Snapdragon 660). Comparison of collected data indicators before and after optimization of 200 frames under the same operation (The demo is at the end of the article)

Before optimization after optimization
优化前 优化后

Monitoring tools from: fps_monitor

  • Fluency: FPS greater than 55, which means less than 18ms per frame
  • Good: FPS between 30-55, i.e. 18ms-33ms per frame
  • Slight lag: FPS between 15-30, i.e. 33ms-67ms per frame
  • Caton: FPS less than 15, which means a frame time greater than 66.7ms

After using frame splitting optimization, the number of lag decreased from an average of 33.3 frames to only one in 200 frames, and the slight lag decreased from 188ms to 90ms. The phenomenon of lag is greatly reduced, the proportion of fluid frames is significantly increased, and the overall performance is smoother. Below are the details.

Before optimization after optimization
The average number of frames appears a lag 33.3 200
The average number of frames with a slight lag 8.6 66.7
Most time consuming 188.0ms 90.0ms
The average time 27.0ms 19.4ms
Fluency frame ratio 40% 64.5%

Page switching fluency improved:

When opening a page or Tab switch, the system will render the entire page and complete the page switch with animation. For complex pages, there will also be a frame lag.

With the framing component, the page build is disassembled frame by frame and viewed through the performance tool in DevTools. During switching, the peak value of a frame is reduced from 112.5ms to 30.2ms, and the overall switching process is more smooth.

image.png image.png

How to use

Project depend on:

Add a dependency on keframe to pubspec.yaml

dependencies:
  keframe: version

Components distinguish only the normal and null-safe versions

The normal version uses : 1.0.3

The null-safe version uses :2.0.6

Quick learning

As shown in the figure below :

image.png

Suppose the page now consists of four parts A, B, C and D, each of which takes 10ms and is built as 40ms at page time.

Use the frameseparateWidget component to nest each section. A simple placeholder is rendered on the first frame of the page, and A, B, C, and D are rendered on the next four frames.

For the list, nested FrameSeparateWidget in each item and nested ListView in SizeCacheWidget.

image.png


Constructor Description:

FrameSeparateWidget :A frame-splitting component that renders nested widgets in a single frame.

type name required describe
Key key no
int index no frame component id, using SizeCacheWidget scenario will pass, and to maintain the index in the SizeCacheWidget corresponding Size information
Widget child yes the actual need to render the widget
Widget placeHolder no placeholder widget, try to set up a simple placeholder, not the default is the Container ()

SizeCacheWidget:Cache size information for **actual widgets nested by framing components in child nodes **.

type name required describe
Key key no
Widget child yes if include framing component in the child nodes, the cache is the actual widget size
int estimateCount no estimates the number of child nodes on the screen, can enhance the response speed of the fast scroll

Example explanation:

Caton's pages are often rendered by multiple complex widgets at the same time. By nested FrameSeparateWidget for complex widgets. When rendering, the Framing Component renders multiple palceHolder simultaneously in the first frame, and then renders complex sub-items in successive frames to improve page fluency.

For example:

ListView.builder(
              itemCount: childCount,
              itemBuilder: (c, i) => CellWidget(
                color: i % 2 == 0 ? Colors.red : Colors.blue,
                index: i,
              ),
            )

The height of cellWidget is 60, and three components of TextField are nested inside (the overall construction time is about 9ms).

Optimization simply involves nested framing components for each item and setting placeHolder for each item (placeHolder should be as simple as possible and should look like the actual item).

In the ListView case, nested SizeCacheWidget is recommended, and the pre-load cacheExtent is recommended to be larger, such as 500 (the default is 250), to improve the slow sliding experience.

For example:

SizeCacheWidget(
              child: ListView.builder(
                cacheExtent: 500,
                itemCount: childCount,
                itemBuilder: (c, i) => FrameSeparateWidget(
                  index: i,
                  placeHolder: Container(
                    color: i % 2 == 0 ? Colors.red : Colors.blue,
                    height: 60,
                  ),
                  child: CellWidget(
                    color: i % 2 == 0 ? Colors.red : Colors.blue,
                    index: i,
                  ),
                ),
              ),
            ),

Here are a few scenarios:

1. The actual item size in the list is known

If the actual item height is known (each item height is 60), just set the placeholder to match the actual item height. See frame optimization 1 in Example.

FrameSeparateWidget(
                index: i,
                placeHolder: Container(
                  color: i % 2 == 0 ? Colors.red : Colors.blue,
                  height: 60,// Keep the same height as the actual item
                ),
                child: CellWidget(
                  color: i % 2 == 0 ? Colors.red : Colors.blue,
                  index: i,
                ),
              )

2. The actual item height in the list is unknown

In the real world, lists are often presented based on data, and there is no way to predict the size of an item at first.

For example, in example frame optimization 2, placeHolder (height 40) is not the same size as the actual item (height 60). Because each item is rendered in a different frame, list jitter occurs.

You can set some approximate height for the placeholder. And nested the ListView in the SizeCacheWidget.

For widgets that have been rendered, the palceHolder size is forced and the cacheExtent is increased. This way, the rendered item will not jump as it slides back and forth.

For example, framing optimization 3 in example

SizeCacheWidget(
              child: ListView.builder(
                cacheExtent: 500,
                itemCount: childCount,
                itemBuilder: (c, i) => FrameSeparateWidget(
                  index: i,
                  placeHolder: Container(
                    color: i % 2 == 0 ? Colors.red : Colors.blue,
                    height: 40,
                  ),
                  child: CellWidget(
                    color: i % 2 == 0 ? Colors.red : Colors.blue,
                    index: i,
                  ),
                ),
              ),
            ),

The actual effect is as follows:

Screenrecording_20210611_194905.gif

3. Estimate the number of items in a screen

If you can roughly estimate the maximum number of actual items that can be displayed on a screen, say 10. Set the SizeCacheWidge estimateCount property to 10*2. Fast scrolling scene builds are more responsive and more memory stable.

For example, framing optimization 4 in example

...
SizeCacheWidget(
              estimateCount: 20,
              child: ListView.builder(
...

In addition, you can also nest animations such as transparency/displacement on items to optimize the visual effect.

The actual effect is as follows:

Screenrecording_20210315_133310.gif Screenrecording_20210315_133848.gif

4. Non-list scenarios

For non-list scenarios, there are generally no fluency issues, but there can still be a lag on first entry.

Similarly, complex modules can be rendered in different frames to avoid first-time entry delays.

For example, we will nest the framing component for the bottom action area in the optimization example:

FrameSeparateWidget(
    child: operateBar(),
    index: -1,
)

The cost of framing

Of course, the framing scheme is not perfect. In my opinion, there are two main costs:

  1. Extra build cost: The build cost of the entire build process changed from "N * widget cost" to "N * (widget + placeholder) cost + The system scheduling N frame cost". As you can see, the additional overhead is mainly due to the complexity of the placeholder. If the placeholders were simple Containers, the overall build time would probably increase by 10-20% after testing.This extra overhead is negligible for today's mobile devices.

  2. Visual change: As demonstrated above, the component will render the item in frames, and the page will visually occupy the space to become the actual widget. But in fact, because the list exists in the cache area (it is recommended to increase the cacheExtent), the user does not feel it in the high-end machine or normal sliding situation. On lower devices, a quick swipe can feel the transition, but it's better than a heavy stumble.


If you have any questions, please feel free to contact me. If this inspires you, dont forget start Thanks

Before and after optimization demo

Before optimization after optimization
优化前 优化后

Contributors

All Contributors

More Repositories

1

BELLE

BELLE: Be Everyone's Large Language model Engine(开源中文对话大模型)
HTML
7,841
star
2

bruno

An enterprise-class package of Flutter components for mobile applications. ( Bruno 是基于一整套设计体系的 Flutter 组件库。)
Dart
3,258
star
3

retrofit-spring-boot-starter

A spring-boot starter for retrofit, supports rapid integration and feature enhancements.(适用于retrofit的spring-boot-starter,支持快速集成和功能增强)
Java
1,762
star
4

fee

灯塔开源文档地址
JavaScript
875
star
5

hetu

低代码平台, 可视化编辑器,单手打代码,解放你的双手
TypeScript
795
star
6

sosotest

sosotest自动化测试平台
Python
509
star
7

kob

中心化的作业调度系统,定义了任务调度模型,实现了任务调度的统一管理和监控。
Java
423
star
8

d18n

d18n is a data desensitization tool for RDBMS.
Go
162
star
9

gson-plugin

辅助 Gson 库的 gradle 插件,防止 Json 数据解析类型异常。
Groovy
151
star
10

Beike_AspectD

Flutter AOP framework. Now compatible with Flutter v3.10.5
Dart
144
star
11

ProgressLayout

A simple Android library about progress layout
Java
89
star
12

flutter_fdb_package

Flutter应用的调试工具,协助采集性能优化、设计走查、QA测试等数据问题 ,提供UI拾取、UI标尺、取色器、内存信息、FPS检测和展示页面代码等功能。
Dart
85
star
13

LJRouter

Objective-C
83
star
14

lightning

lightning is a tool for binlog parsing. It can generate original SQL or flashback SQL.
Go
74
star
15

ke-ve

一站式的可视化服务集成平台
JavaScript
58
star
16

bk_flutter_image

flutter image,降低内存使用
Dart
48
star
17

flutter_ui_auto_test

贝壳 flutter UI 自动化测试
Dart
47
star
18

json-diff

A tool for find difference between two json-string. Support JSON string depth comparison, support JSON array unordered comparison. (用于比较两个JSON字符串的工具,支持JSON字符串深度比较,支持无序数组比较)
Java
46
star
19

dgraph-sql

Java
40
star
20

athena

An open-source implementation of sequence-to-sequence based speech processing engine
C++
38
star
21

Snap

网页截图
JavaScript
34
star
22

kbms

一个轻量级c++网络框架
C++
31
star
23

UIC

User Information Center
Go
30
star
24

flutter_beike_engine

C++
25
star
25

bucky-core

bucky框架核心模块
JavaScript
14
star
26

cicada-ci

TypeScript
12
star
27

BKFlutterWebNativeBridge

Flutter Web和Flutter Mobile桥接。
Objective-C
9
star
28

benchmark

Objective-C
8
star
29

newsboy

web platform to manage api, support mock service and api test
JavaScript
8
star
30

ked

ked 是基于 Ke Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。
TypeScript
4
star
31

bucky-cli

bucky框架业务使用脚手架
JavaScript
3
star
32

Storm-Counter

Storm consumer command queue from Kafka, then parse and excute command to storage numbers into Hbase
Java
2
star
33

athena-model-zoo

Athena-model-zoo can provide a lot of kinds of pre-trained models to be used for others.
2
star
34

gson-plugin-sdk

gson-plugin依赖这个sdk
Java
1
star