Flutter 作为一个优秀的跨平台UI库,跨平台的宿主包含 iOS 、Android、Web。那Flutter 是如何配合线程,完成UI绘制渲染,事件响应等。
dart 代码是在哪个线程工作,组件是如何绘制渲染的,事件是如何响应的。带着上述的问题,我将从宏观的角度来研究一下Flutter
,
Flutter 使用多个线程来完成其工作,但叠加层中只显示了其中两个线程。所有 Dart 代码都在 UI 线程上运行。尽管您无法直接访问任何其他线程,但您在 UI 线程上的操作会对其他线程产生性能影响。
平台线程(宿主程序的主线程,iOS & Android的主线程)
UI线程
UI线程在Dart VM中执行Dart代码。该线程包含您编写的代码以及 Flutter 框架代表您的应用程序执行的代码。当您的应用程序创建并显示场景时,UI 线程会创建一个图层树(一个包含与设备无关的绘画命令的轻量级对象),并将图层树发送到光栅线程以在设备上渲染。不要阻塞此线程! 显示在性能叠加层的底行中。
光栅线程(以前的GPU线程)
光栅线程获取图层树并通过与 GPU(图形处理单元)通信来显示它。您无法直接访问光栅线程或其数据,但是,如果该线程速度缓慢,则可能是您在 Dart 代码中执行某些操作的结果。Skia 和 Impeller 图形库在该线程上运行。显示在性能叠加层的顶行中。该线程以前称为“GPU 线程”,因为它针对 GPU 进行光栅化。但它是在CPU上运行的。我们将其重命名为“光栅线程”,因为许多开发人员错误地(但可以理解)假设线程在 GPU 单元上运行。
I/O线程
执行昂贵的任务(主要是 I/O),否则会阻塞 UI 或光栅线程。该线程未显示在性能覆盖图中。
Flutter
中一切接组件,关于 dart.FrameWork
中涉及的五层框架,Materia
, Cupertino
是对低层widget
的抽象,关于lv1层库中的组件比较常见的floatedButton, Scaffold, TextField、Activity
等使用的的比较多。
关于Flutter渲染树:这里着重涉及到
RenderObject
,Flutter Widget 组件库通过使用RenderObject
的层级,来实现布局和后台绘制。一般来说,虽然您可以RenderBox
在应用程序中使用自定义类来实现特定效果,但大多数时候您与RenderObjec
t层次结构的唯一交互是调试布局问题。
上述引用源于此处
匆匆一瞥,有些难以理解。我们打开dart.framework
来一探究竟。目录flutter/lib/src/rendering
, 我们找到box.dart
。
引用说明的RenderBox
自定义可在此处注视中说明
// Examples can assume:
// abstract class RenderBar extends RenderBox { }
// late RenderBox firstChild;
// void markNeedsLayout() { }
RenderBox
的定义片段
abstract class RenderBox extends RenderObject {
double _computeIntrinsicDimension(_IntrinsicDimension dimension, double argument, double Function(double argument) computer) {
}
...
}
自造
关于RenderBox 比较底层的Widget,RenderBox实现了布局算法(提供了BoxConstraint). RenderBox 的事件传递,是通过实现HitTest
方法的。关于事件的传递,可以参考1301的注释。
此处是绘制 手势 动画和引擎通信的低层API此处,暂不展开。
我们使用flutter create
, 创建了一个计数器项目。既然Flutter是一个UI框架,上述又唠了很多关于RenderObject
的事情,不眠有些疑惑,flutter 到底是如何布局的,RenderObject是怎么连接到Widget的,那说了500遍的三棵树有何关系。
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
事例中涉及到了Scaffold
, AppBar
, Center
, Column
, floatingActionButton
, Text
, Icon
等Widget
, runApp
后到底发生了什么。
flutter
作为一个声明式的UI框架,我们创建的Widget 是对组件结构的描述,我们看到的Text
Widget和原生中的UILabel
是不一样的,这里通过修改flutter 的状态,来修改Text的值。这里暂且不讲状态,所以就来到我们这边的第一个知识点,WidgetTree。那么Widget树中的节点,Widget 又做了什么呢,