Flutter 的可视化界面、绘制性能调优 🔧 —— DevTools

前言

给你们介绍DevTools的主要缘由主要有几点 🚀 :git

  • 首先是DevTools自己是Flutter官方推荐的一个调试工具。
  • DevTools是用Flutter编写的,极具特点 🖼 。
  • 拥有很是全面的调试功能,能够知足大小、方面不一样的优化需求 ⚙️。

DevTools

首先,隆重介绍今天的主角:DevTools 👏web

官网介绍:DevTools is a suite of performance and debugging tools for Dart and Flutter. It’s currently in beta release, but is under active development.编程

翻译:DevToolsDartFlutter的一套性能和调试工具。它目前处于测试版,但正在积极开发中。后端

安装 🔌

要使用DevTools首先,全部的一切的前提,确定是,装上它,yes,这看似简单的一步其实花了我还蛮久时间的。但愿各位安装顺利,我将给各位介绍四种打开DevTools的方法浏览器

Android Studio / Intellij

使用以上两种开发工具的小伙伴看这边了 🙋‍♂️,在此类开发工具上打开DevTools一共分三个步骤markdown

  1. 安装 Flutter 插件:

首先确认你已经在开发工具内安装了Flutter 插件(不会有人还没装吧,不会吧 👀 )



app

  1. 开始调试一个应用 🔩

对,就是字面意思,容许你要调试的那个项目工程(推荐使用Profile模式)。友情提示:Profile模式只能在真机 📱 上运行。异步

  1. 找到 DevTools 的入口

其实 DevTools 的入口不是很显眼,可是还算好找,在底部的工具栏,我们常常用的hot reload边上,直接点击该按钮 🔘 就能够启动该项目的DevTools

函数

(PS:我本身用的是Android Studio,可是我并无经过这种方式成功,一直就是Installing DevTools...,若是各位知道缘由,欢迎在评论区指点一下,阿里嘎多 🤗 )工具

VS Code

  1. 安装 Flutter 插件:

首先确认你已经在开发工具内安装了FlutterDart 插件(同Android Studio

  1. 经过在 VS Code 中打开你的项目的根目录(包含 pubspec.yaml)并点击 Run > Debugging (F5),来开启调试会话。

  2. 启动开发程序

  • 一旦调试会话处于活跃且应用程序已开启 🏃🏻 ,那么 VS Code 命令控制板中将会显示 Dart: Open DevTools

  • 当你第一次运行时(以及将来更新开发工具包时),系统会提醒你激活或升级DevTools

Command Line (命令行)

  1. 安装开发者工具

若是在你的环境变量 PATH 中有 pub, 能够运行 🚀:

pub global activate devtools
复制代码

若是环境变量 PATH 中有 flutter , 能够运行 🚀:

flutter pub global activate devtools
复制代码
  1. 启动开发者工具服务

下一步,启动本地 web server 服务来运行开发者工具。运行下面两个命令中的一个。

pub global run devtools   # If you have `pub` on your path.
复制代码
flutter pub global run devtools   # If you have `flutter` on your path.
复制代码

运行这两行代码以后,在命令行应该会有这样一个输出:

An Observatory debugger and profiler on iPhone X is available
at: http://127.0.0.1:50976/Swm0bjIe0ks=/
复制代码

at后面的就是DevTools的地址,你们直接用Chrome打开便可。打开后的网页须要你填写一个连接,也就是你须要调试的项目的Debug service监听地址,这个地址哪儿来的呢 🤔 ?



3. 启动一个 appdebug

其实上面所需的连接 🔗 地址,就在咱们平时运行项目的Log中。你们运行工程,在日志的前几行就能够找到Debug service的地址,就是图中 listening on以后的部分,将该连接填入咱们在第二步打开的网页中,就能够进入到咱们项目对应的DevTools之中。

暴力打开

以上三种是Flutter官网提供的安装、打开方式,很惋惜,我都没有打开成功 🤯 ,不是一直安装,就是打开了一个很是老的版本的DevTools,应该是和个人Dart SDK路径配置有关,因此通过个人研究,发现了一个很是痛快 🤫 的打开方法(目前暂不知有什么弊端)。

  1. 找到Flutter文件夹的地址。

这个因人而异,各位应该清楚本身电脑上flutter的路径吧,好比我就放在我的的development目录下:

/Users/tys/development/flutter
复制代码
  1. 找到DevTools

这就是我这边要说的暴力打开的关键 🔑 ,我发现...,这个DevTools,好像已经悄悄的放在了Flutter中。

/Users/tys/development/flutter/.pub-cache/bin/devtools
复制代码

在上面这个目录下,你们能够直接找到它,双击点开,直接好家伙 💡



芜湖~直接到达上面用命令行打开的最后一步。并且这就是你当前使用的Flutter版本对应的最新的、可用的DevTools

使用 DevTools🕵🏻‍♂️‘

我将按照DevTools顶部工具栏的顺序给各位逐个介绍各个功能 🤓 。

Flutter inspector

  • 简介:这一部分的功能主要是面向各位的界面模块,里面首先会展现你总体的布局绘制树 🌲 ,点击树的每一个节点都会在右侧显示更细节的布局信息 🐳 ,同时,在布局信息上你能够看到可视化的视图信息并进行一些简单的选择操做,这部分功能用官方的话说主要有两个目的:

  1. 了解现有布局。
  2. 诊断布局问题。

  有关这个模块的内容咱们根据下图中红色标注的顺序一块儿看一下 🔍

Select widget mode

  这实际上是一个选择视图,你们看到这个Tab下对应的其实就是你的整个绘制树 🌲 了,这样一颗树的结构复杂度通常都会和你的页面复杂度相关。若是是一个复杂的页面结构,这棵树也会很是庞大,看起来会很模糊,为了让咱们能够更好的看到树里面的细节结构,咱们就能够点击树上的某个节点,区查看树的某一部分的详细内容 🔮 。

Detail Tree

  顾名思义,其实这里就是咱们刚才所选择的节点的详细信息,其实现实的信息真的能够说很是走心 ❤️ 了。看图中,我选了一个Container节点 ,Container下的未赋值属性都给你提示出来了,如bg背景颜色等。若是你的页面内有颜色、色彩的叠加之类的,经过它能够看的很清晰 🔬 。

Layout Explorer

   这个就厉害了,是你当前选中节点的布局浏览器。好比你们能够看到,我选中的这个Container下面有包裹的详细结构都有显示出来,包括各个Wiget的边界,甚至给你显示了计算后的高度和宽度 📏 (按照标准的分辨率尺寸)。


  Layout Explorer不只能让你查看整个布局界面,还可让你作一些简单的动态操做,让你在不改动代码的前提下,明确你的布局问题,或者缺陷(请看动图⬇️ )。

Slow Animations

  点击该按钮,将下降你App内的全部动画效果的速度,感觉0.5倍速的神奇世 🤩 ,这里说的Animations包括但不只限于你的界面跳转,Hero等系统级动画,我的认为这部分功能主要有两个做用

   1. 若是在该模式下你的动画不存在任何卡顿,则说明你的动画效能很是完美,能够达到比较好的用户体验 👍 。
   2. 让部分动画制做者看清本身的动画绘制曲线、路径 🕳 。

Debug Paint

  在渲染中添加视觉调试提示,以显示边框,填充,对齐和间隔。会在你的模拟器上显示总体的布局状况,这些状况包括你的总体渲染方向和基础组件类。

Paint Baselines

  使每一个RenderBox在其每一个文本基线处绘制一条线。就是下图中的绿线 ⬇️

Repaint Rainbow

  打开这个功能,你的界面在重绘时,会在重绘的部分更改一个边界颜色 🎆 。好比,你有一个banner,间隔1s换一张图片,那么每一秒你的banner图周边的颜色就会变一个随机颜色。我的感受其目的是让咱们看到当前页面正在绘制或重绘的部分。

Timeline 🌟

在进行性能调试时请使用实际设备调试。Skia有两套很不一样的后端,Flutter在iOS模拟器中使用纯CPU后端,而在实际设备通常使用GPU硬件加速后端,因此性能特性很不同。

TimeLineDevTools中比较实用有实际意义的部分。可让你实际看到你的APP存在的UI问题或GPU问题。接下来我将带各位来学习如何去分析本身Flutter APP的绘制性能 🩺 。


  你们首先能够看到,在上图中最上层的部分是一个柱形图 📊 。这部分是你刚才所作操做的一个绘制状态图,根据右边的图例,也能明白其中的意思,这边我再给各位明确一下。

UI、Raster、Jank

  你们看柱状图中有红色有蓝色,淡蓝色的是UI线程的绘制状况、深蓝色是你的栅格化线程(GPU线程)。红色,表明你的绘制出现了卡顿。通常来讲咱们在Flutter里咱们定义卡顿:若是一帧的渲染时间超过16ms,则会被认为此帧是延时的,为了达到帧渲染频率到 60 FPS (每秒帧数),每一帧的渲染时间必须等于或少于 16 ms。若是没有达到这个目标,你会发现 UI 不流畅或丢帧 📌 。

Timeline Event

  咱们在整个界面的中间部分能够看到的是Timeline Event,它其实对应的就是咱们上面绘制状况图的细节状况,是绘制过程当中的事件。咱们利用它能够详细的看见咱们卡顿的缘由。咱们挑选其中卡顿的一帧,来仔细分析一下 🧮 。
  在下图中你们能够看到在Timeline Event中,依然分为了两个部分,上半部分是UI Event,下半部分是Raster Event。在这一阵中,咱们能够明显的感受到的是,咱们的UI Event占用了很是长的时间 ⏰ 。为了你们能对整个TimeLine Event的含义有更好的理解,这里引用了官方的一段解释:

火焰图选项卡用于显示选中帧事件,CPU 的样本信息。图表展现的是自上而下的调用堆栈信息,即上面的堆栈帧调用下面的堆栈帧。每个堆栈帧的宽度表明 CPU 执行的时长。栈帧消耗 CPU 的时间越长,就越洽有多是咱们进行性能改进的好地方。

  咱们在上面的堆栈信息中能够看到最上层的一个EventVsyncProgressCallback,在下图中,咱们能够在底部看到,这个堆栈的耗时高达40.6ms,几乎是没法接受的🚽 。其实咱们点击一个流畅的帧后,发现其中也会有VsyncProgressCallback。那么为何这一帧会格外的长,并形成卡顿呢?

  所以咱们为了进一步探究其中的缘由,咱们须要进一步的深刻探究,咱们须要更多的信息。

  • 更详细的火焰图 🔥 (CPU Flame Chart

  这里有你想要的细节信息,包括内部具体某一个堆栈的耗时状况。为什么VsyncProgressCallback耗时如此之久。内部有哪些细节操做,这里一清二楚 🐮 。这里咱们能够看到,一个长耗时VsyncProgressCallback相比一个短耗时的VsyncProgressCallback多了几个部分。在清楚VsyncProgressCallback的内部堆栈信息后,咱们就能够有针对性的再对内部的耗时堆栈进行分析。切换到咱们第二个Tab

有关Flutter中的Vsync信号推荐阅读: Flutter渲染机制 - UI线程 🔗 。

  • 调用树

  这部分更贴近咱们开发者,咱们能够详细看到VsyncProgressCallback具体调用了哪些函数,哪些函数是耗时比较久的。你们再结合上面一张图,咱们在卡顿这一帧多作的工做,或者说多调用的函数,就是这里的performRebuild,点开函数的具体调用,咱们能够发现,这个函数一直在循环调用。没错这里的performRebuild其实就是一个遍历你绘制树 🌲 的过程,说明了你在当前帧,更新了一个庞大的绘制树,而且树上的多个子节点也进行了从新绘制。因此咱们应该要排查的就是,咱们在界面中的哪一个部分集中调用了多个组件的重绘,或者哪部分的view_mode,驱动了这样的一个重绘过程,其中是否有没必要要的重绘。以此来提升渲染性能 😆 。

  上面一部分说明了咱们的UI线程阻塞的部分缘由,和排查方法,那若是是GPU呢?一样,咱们选取了一帧典型的GPU耗时操做,在这个堆栈信息中咱们能够看到咱们的GPU方法确实占用了大量的时间 ⏳ ,一样是GPURasterizer::Draw为何某一帧会特别久呢?

  其实在DevToolsRaster视图中,并不能将这部分展现的很是清晰。可是还有一个办法能够深究其缘由。你们能够直接打开以前填入DevTools的连接。若是你正在profile模式下运行,你的log中就能够找到这个连接 🔗 。

  点开这个连接,在这个页面的中间部分,咱们能够找到timeline工具(我已经在图中用红框标出)。

  进入这部分timeline以后,这里就是最最最最详细的每一帧的信息了 📌 。你能够用鼠标选中一块区域,在下方就会输出你选中区域的具体函数调用状况。包括函数名称、总耗时、调用次数、每次耗时以及一个可视化的柱状图 📊 占比状况。一目了然。有关GPU部分的函数调用须要各位对Flutter Engine的源码有比较高的理解,才能有针对性的解决问题。其中相关的调用栈很是的复杂。

  官方声明的会大量耗时的skia函数调用:

  • saveLayer: 很是耗时,每次调用须要在CPU里从新分配一块绘图缓冲区,而且告诉GPU切换绘图目标。尤为在比较老的设备上。
  • clipPath: 耗时,每次调用,会影响接下来每个绘图指令,当绘图指令复杂时,会作屡次和clipPath的相交操做,把在clipPath以外的部分剔除。

  可能你们会说,这部分函数,平时在编程的时候几乎没有使用 🤯 ,但其实他们普遍存在于咱们常见的Widget及其属性中。好消息是Flutter Team在过去的更新迭代中已经剔除了很是多的没必要要的相似上述的耗时操做 🐳 。因此当你们在本身的timeline中找到相似的耗时操做后,仍是能够经过一些Widget的组件源码去分析找到出处,相较之前容易得多。

在上图的函数调用状况图中,短耗时的操做不表明其没有可能形成卡顿。有可能你找到了saveLayer的调用,但没有想象中的耗时。实际是由于:Skia的GPU的后端在接收到saveLayer的指令后会进行一个简单的预处理,就当即返回,形成不耗时的假象。但实际后续异步的过程当中还会调用SkCanvas::Flush形成大量耗时。这里异步处理的目的是将多条预处理消息打包 📦 送至GPU进行绘制。

结束语

   有关Flutter中的界面绘制性能相关就介绍到这里了,但愿这篇文章能给各位起到必定的帮助做用 🤪 ,后续会继续介绍Flutter相关的内存管理和其余相关知识,敬请期待 🧸 。
   参考:DevTools

相关文章
相关标签/搜索