奇技指南 在【360互联网技术训练营第17期——Flutter
开发者沙龙】上,360资深Android工程师刘圣文分享了《Flutter从加载到显示》。本文是具体内容。
主要内容
本文将主要为大家介绍下面三部分内容:
1、Widget、Element、RenderObject基本概念
2、在Flutter Framework层从创建到渲染的流程
3、Flutter在构建布局方面是如何提高效率的
什么是Flutter?
Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。它也是构建未来的Google Fuchsia 应用的主要方式。
框架结构
Flutter的主要结构包括:
-
Flutter engine
-
Flutter framework
我们看一下这个形象又生动的架构图片:
Framework层
我们来看一下有关部分:
Material 是谷歌UI设计规范、Cupertino 是苹果UI设计规范,我们日常开发经常用这两部分。
Widgets 应用程序用户界面的基本组件,也就是我们开发者在UI开发时着重要处理的部分,官方给到解释是描述Element的配置。
Rendering 抽象布局层,这一层帮助我们完成渲染的初步工作,比如UI元素的位置、大小、绘制等等。
Animation、Painting、Gestures,在代码里面对应的是Dart:UI包,属于底层UI库,主要提供动画、绘制、手势功能。
Foundation 基础工具库
以上就是Framework层,这一层也正是Flutter精髓所在。
Engine层
Skia是2D图像渲染引擎、Dart运行时,Text文字处理引擎。
这个架构图中开发者着重关注Widget开发工作、Material与Cupertino的使用,其他不需要太关心,这些Flutter团队已经帮普通开发者完成了,但是如果稍作了解,对我们对开发还是有很大帮助的。
接下来我们一起开始源码分析之旅吧^^

这样的页面Flutter Framework是如何处理的?
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 这个widget是应用程序的根
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Hello 360'),
);
}
}
我们可以看到在main方法处,调用了runApp方法,这就是Flutter开始加载渲染的入口了。值得我们注意,调用runApp(MyApp()),一般Flutter启动时调用,之后就不再会调用了。这里的MyApp(),就是开发者自定义的rootWidget,即widget的根。也就是这里extends StatelessWidget组件。
简单的公式描述
我们知道Flutter的实现有Flutter Framwork 和 Engine两大部分组成,不言而喻,从加载到显示地整个渲染流程极其复杂。从进入runApp方法开始到屏幕上显示出来这个过程,我们可否用一个简单的方程式来简单描述一下呢?
1、state就是我们Application内的那些逻辑和内部状态;
2、f() 表示用来描述用户界面部分的方法,比如:build方法调用;
3、UI 屏幕上显示的布局视图;
这个方程式很形象生动的描述了这个state变化到UI渲染完成显示的过程。
Widget、Element、RenderObject基本概念
先为大家介绍一下涉及到的几个关键词:
Widget
Widget :小部件,也就是我们开发者在UI开发时着重要处理的部分,官方给到解释是:描述Element的配置信息,属于不可变对象,它的属性是final修饰。
BuildContext
用来获取上下文的数据,它实际就是Element,BuildContext是为了开发者不直接操作Element而抽象出来的类,所有Element都继承自BuildContext这个抽象类。
Element
表示Widget在树中特定位置的一个实例。因为widgets是不可变的,所以同一个widgets可以同时配置到多个子树。[Element]的配置表示了widget在树中的特定位置。父widget重新构建时会给该位置创建一个新的widget,与给定元素关联的widget就会更改。大多数元素都有一个惟一的子元素,但是有些widget(例如[RenderObjectElement]的子类)可以有多个子元素。
RenderObject
表示在渲染树RenderTree上的节点对象。布局绘制工作都跟他有直接关系。
Window
Window是Flutter Framework连接宿主操作系统的接口。这里看一下,有关Window的源码
class Window {
// 当前设备的DPI
double get devicePixelRatio => _devicePixelRatio;
// Flutter绘制区域的大小
Size get physicalSize => _physicalSize;
// 当绘制区域大小改变回调
VoidCallback get onMetricsChanged => _onMetricsChanged;
// 绘制前回调,一般会受显示器的垂直同步信号VSync驱动,当屏幕刷新时就会被调用
FrameCallback get onBeginFrame => _onBeginFrame;
// 绘制回调
VoidCallback get onDrawFrame => _onDrawFrame;
// 调度Frame,该方法执行后,onBeginFrame和onDrawFrame将紧接着会在合适时机被调用,
// 此方法会直接调用Flutter engine的Window_scheduleFrame方法
void scheduleFrame() native 'Window_scheduleFrame';
// 更新应用在GPU上的渲染,此方法会直接调用Flutter engine的Window_render方法
void render(