flutter 创建应用_Flutter多快? 我建立了一个秒表应用程序来查找。

flutter 创建应用

by Andrea Bizzotto

通过安德里亚·比佐托(Andrea Bizzotto)

Flutter多快? 我建立了一个秒表应用程序来查找。 (How fast is Flutter? I built a stopwatch app to find out.)

This weekend I had some time to play with the new Flutter UI framework by Google.

这个周末,我有一些时间来使用Google的全新Flutter UI框架。

On paper it sounds great!

在纸上听起来很棒!

According to the docs, high performance is to be expected:

根据docs ,预期会有高性能:

Flutter is designed to help developers easily achieve a constant 60fps.
Flutter旨在帮助开发人员轻松实现恒定的60fps。

But what about CPU utilization?

但是CPU利用率呢?

TL;DR: Not as good as native. And you have to do it right:

TL; DR :不如本地人。 而且您必须正确地执行以下操作:

  • Frequent UI redraws are expensive

    频繁的UI重绘很昂贵
  • If you call setState() often, make sure it redraws as little UI as possible.

    如果经常调用setState() ,请确保它重绘了尽可能少的UI。

I built a simple stopwatch app in Flutter and profiled it to analyze CPU and memory usage.

我在Flutter中构建了一个简单的秒表应用,并对其进行了分析,以分析CPU和内存使用情况。

实作 (Implementation)

The UI is driven by two objects: a stopwatch and a timer.

UI由两个对象驱动: 秒表计时器

  • The user can start, stop and reset the stopwatch by tapping on two buttons.

    用户可以通过点击两个按钮来启动,停止和重置秒表。
  • Each time the stopwatch is started, a periodic timer is created with a callback that fires every 30ms and updates the UI.

    每次启动秒表时,都会创建一个定期计时器,该计时器每30ms触发一次回调并更新UI。

The main UI is built like this:

主UI的构建如下:

How does this work?

这是如何运作的?

  • Two buttons manage the state of the stopwatch object.

    两个按钮管理秒表对象的状态。
  • When the stopwatch is updated, setState() is called, triggering the build() method.

    当秒表更新时,将调用setState() ,触发build()方法。

  • As part of the build() method, a new TimerText is created.

    作为build()方法的一部分,将build()一个新的TimerText

The TimerText class looks like this:

TimerText类如下所示:

A couple of notes:

一些注意事项:

  • The timer is created along with the TimerTextState object. Each time the callback fires, setState() is called if the stopwatch is running.

    计时器与TimerTextState对象一起创建。 每当秒表正在运行时,每次触发回调时都会调用setState()

  • This causes the build() method to be called, which draws a new Text object with the updated time.

    这将导致build()方法被调用,该方法将绘制一个具有更新时间的新Text对象。

做对了 (Doing it right)

When I first built this app, I was managing all the state and UI in the TimerPage class, which included both the stopwatch and the timer.

首次构建此应用程序时,我正在管理TimerPage类中的所有状态和UI,其中包括秒表和计时器。

This meant that each time the timer callback was fired, the entire UI was re-built. This is redundant and inefficient: only the Text object containing the elapsed time should be redrawn — especially as the timer fires every 30ms.

这意味着每次触发计时器回调时,都会重新构建整个UI。 这是多余且效率低下的:仅应重绘包含已用时间的Text对象,尤其是当计时器每30ms触发一次时。

This becomes apparent if we consider the un-optimised and optimised widget tree hierarchies:

如果考虑未优化和优化的小部件树层次结构,这将变得显而易见:

Creating a separate TimerText class to encapsulate the timer logic is less CPU-intensive.

创建一个单独的TimerText类来封装计时器逻辑不会占用大量CPU。

In other words:

换一种说法:

  • Frequent UI redraws are expensive

    频繁的UI重绘很昂贵
  • If you call setState() often, make sure that it redraws as little UI as possible.

    如果经常调用setState() ,请确保它重绘了尽可能少的UI。

The Flutter docs state that the platform is optimised for fast allocation:

Flutter文档指出该平台已针对快速分配进行了优化:

The Flutter framework uses a functional-style flow that depends heavily on the underlying memory allocator efficiently handling small, short-lived allocations
Flutter框架使用一种功能样式的流程,该流程在很大程度上取决于基础内存分配器,可以有效地处理较小的,短暂的分配

Perhaps rebuilding a widget tree doesn’t count as “small, short-lived allocation”. In practice, my code optimisations resulted in a lower CPU and memory usage (see below).

重建小部件树可能不算作“小而短暂的分配”。 实际上,我的代码优化导致CPU和内存使用率降低(请参见下文)。

更新19–03–2018 (Update 19–03–2018)

Since publishing this article, some Google engineers took notice and kindly contributed with some further optimisations.

自从发布本文以来,一些Google工程师注意到了这一点,并为进一步的优化做出了贡献。

The updated code further reduces UI redrawing by splitting TimerText into two MinutesAndSeconds and Hundredths widgets:

通过将TimerText分为两个MinutesAndSecondsHundredths小部件,更新后的代码进一步减少了UI重绘:

These register themselves as listeners to the timer callback, and only redraw when their state changes. This further optimises performance as only the Hundredths widget now renders every 30ms.

它们将自己注册为计时器回调的侦听器,并且仅在其状态更改时才重画。 这现在进一步优化了性能,因为现在只有每30毫秒渲染一次“ Hundredths小部件。

基准测试结果 (Benchmarking results)

I ran the app in release mode (flutter run --release):

我在发布模式下flutter run --release了该应用程序( flutter run --release ):

  • Device: iPhone 6 running iOS 11.2

    设备:运行iOS 11.2的 iPhone 6

  • Flutter version: 0.1.5 (22 Feb 2018).

    Flutter版本: 0.1.5 (2018年2月22日)。

  • Xcode 9.2

    Xcode 9.2

I monitored CPU and memory usage in Xcode for three minutes, and measured the performance of the three different modes.

我在Xcode中监视了三分钟的CPU和内存使用情况,并测量了三种不同模式的性能。

非优化代码 (Non optimized code)
  • CPU Usage: 28%

    CPU使用率:28%
  • Memory usage: 32 MB (from a baseline of 17 MB after app start)

    内存使用情况:32 MB(从启动应用程序后的17 MB开始)
优化阶段1(单独的计时器文本小部件) (Optimization pass 1 (separate timer text widget))
  • CPU Usage: 25%

    CPU使用率:25%
  • Memory usage: 25 MB (from a baseline of 17 MB after app start)

    内存使用量:25 MB(从启动应用程序后的17 MB开始)
优化阶段2(分别为分钟,秒和百分之一) (Optimization pass 2 (separate minutes, seconds, hundredths))
  • CPU Usage: 15% to 25%

    CPU使用率:15%到25%
  • Memory usage: 26 MB (from a baseline of 17 MB after app start)

    内存使用量:26 MB(从启动应用程序后的17 MB开始)

On this last test, the CPU usage graph tracks closely the GPU thread, while the UI thread stays fairly constant.

在上一次测试中,CPU使用率图密切跟踪GPU线程,而UI线程保持相当恒定。

NOTE: running the same benchmark in slow mode yields CPU usage over 50%, and memory usage increasing steadily over time.

注意 :在慢速模式下运行相同的基准会导致CPU使用率超过50%,并且内存使用率会随着时间稳定增长

This may point to memory not being deallocated in development mode.

这可能表明内存没有在开发模式下释放。

Key takeaway: make sure to profile your apps in release mode.

重点: 确保在发布模式下配置您的应用程序

Note that Xcode reports a very high energy impact when CPU usage is over 20%.

请注意,当CPU使用率超过20%时,Xcode报告对能量的影响非常大

深层发掘 (Digging deeper)

The results got me thinking. A timer which fires ~30 times per second and re-renders a text label should not use up to 25% of a dual core 1.4GHz CPU.

结果让我开始思考。 每秒触发〜30次并重新渲染文本标签的计时器最多不能使用双核1.4 GHz CPU的 25%。

The widget tree in a Flutter app is built with a declarative paradigm, rather than the imperative programming model used in iOS / Android.

Flutter应用程序中的小部件树是使用声明性范式构建的,而不是在iOS / Android中使用的命令式编程模型。

But is the imperative model more performant?

但是命令式模型是否表现更好?

To find out, I have built the same stopwatch app on iOS.

为了找出答案,我在iOS上构建了相同的秒表应用程序。

This is the Swift code to setup a timer and update a text label every 30ms:

这是Swift代码,用于设置计时器并每30ms更新一次文本标签:

For completeness, here is the time formatting code I used in Dart (optimization pass 1):

为了完整起见,这是我在Dart中使用的时间格式代码(优化过程1):

The final results?

最终结果?

Flutter. CPU: 25%, Memory: 22 MB

扑。 CPU:25%,内存:22 MB

iOS. CPU: 7%, Memory: 8 MB

iOS。 CPU:7%,内存:8 MB

The Flutter implementation is over 3x heavier on CPU, and uses 3x as much memory.

Flutter的实现在CPU上要重3倍以上,并使用3倍的内存。

When the timer is not running, CPU usage goes back to 1%. This confirms that all CPU work goes into handling the timer callbacks and redrawing the UI.

当计时器未运行时,CPU使用率将恢复为1%。 这确认所有CPU工作都用于处理计时器回调和重新绘制UI。

This is not entirely surprising.

这并不完全令人惊讶。

  • In the Flutter app, I build and render a new Text widget every time.

    在Flutter应用程序中,每次都构建并渲染一个新的Text小部件。

  • On iOS, I just update the text of a UILabel.

    在iOS上,我只更新UILabel的文本。

“Hey!” — I hear you saying. “But the time formatting code is different! How do you know that the difference in CPU usage is not due to this?”

“嘿!” —我听你说。 “但是时间格式代码不一样! 您怎么知道CPU使用率的差异不是由于这个原因?”

Well then, let’s modify both examples to do no formatting at all:

那么,让我们修改两个示例以完全不进行格式化:

Swift:

Swift:

Dart:

镖:

Updated results:

更新结果:

Flutter. CPU: 15%, Memory: 22 MB

扑。 CPU:15%,内存:22 MB

iOS. CPU: 8%, Memory: 8 MB

iOS。 CPU:8%,内存:8 MB

The Flutter implementation is still twice as CPU-intensive. Additionally, it seems to do quite a bit of stuff on multiple threads (GPU, I/O work). On iOS, only one thread is active.

Flutter实施仍然是CPU密集型的两倍。 此外,它似乎在多个线程上做了很多工作(GPU,I / O工作)。 在iOS上,只有一个线程处于活动状态。

结论 (Conclusion)

I have compared the performance of Flutter/Dart vs iOS/Swift on a very specific use case.

我在一个非常特定的用例上比较了Flutter / Dart与iOS / Swift的性能。

The numbers don’t lie. When it comes to frequent UI updates, you can’t have your cake and eat it, too. ?

数字不会说谎。 当涉及到频繁的UI更新时, 您也不能吃蛋糕 。 ?

Flutter lets developers create apps for both iOS and Android with the same codebase. And features such as hot reloading further accelerate productivity. Flutter is still in its early days. I hope that Google and the community can improve the runtime profile, so that these benefits are carried over to the end-users.

Flutter使开发人员可以使用相同的代码库为iOS和Android创建应用程序。 热重装等功能进一步提高了生产率。 Flutter仍处于起步阶段。 我希望Google和社区可以改善运行时配置文件,以便将这些好处带给最终用户。

As for your apps, consider fine-tuning your code to minimize UI redraws. It is well worth the effort.

对于您的应用程序,请考虑对代码进行微调以最大程度地减少UI重绘。 这是值得的。

I have added all the code for this project on this GitHub repo, so you can play with it yourself.

我已经在GitHub存储库中添加了该项目的所有代码,因此您可以自己使用它。

You’re welcome! ?

别客气! ?

This sample project was my first experiment with Flutter. If you know how to write more performant code, I’d love to hear your comments.

这个示例项目是我对Flutter的第一个实验。 如果您知道如何编写更多性能代码,我很想听听您的评论。

About me: I’m an iOS & Flutter developer, juggling between contract work, open source, side projects and blogging.

关于我:我是iOS和Flutter开发人员,在合同工作,开源,副项目和博客之间徘徊。

I’m @biz84 on Twitter. You can also see my GitHub page. Feedback, tweets, funny gifs, all welcome! My favorite? Lots of ???. Oh, and banana bread.

我在Twitter上为@ biz84 。 您还可以看到我的GitHub页面。 反馈,推文,有趣的GIF,欢迎您! 我的最爱? 很多 ???。 哦,还有香蕉面包。

翻译自: https://www.freecodecamp.org/news/how-fast-is-flutter-i-built-a-stopwatch-app-to-find-out-9956fa0e40bd/

flutter 创建应用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值