1、Widget
StatelessWidget和StatefulWidget都继承自Widget。
Widget作为虚类,定义了Element createElement()
方法,给继承者实现,返回Element对象。
具体到StatelessWidget,实现createElement,返回StatelessElement对象。StatelessElement继承自ComponentElement。
具体到StatefulWidget,实现createElement,返回StatefulElement对象。StatefulElement继承自ComponentElement。
ComponentElement继承自Element类。
在执行createElement方法时,都会把Widget传递给Element对象,因此Element持有一个Widget对象。
2、Element
在Element树的特定位置,Element代表一个Widget实例。
多个Element形成了一颗Element树,大多数Element有一个独一无二的child,但是那些继承自RenderObjectElement的Element,就可以有多个child.
通过调用Widget.createElement方法创建一个Element,通过调用Element的mount方法,将一个新的Element添加到一个父Element的属性为slot的位置。
Element类的mount方法,负责填充所有的子Widget,并在必要时调用attachRenderObject方法,将关联的渲染对象(render objects)附着到渲染树,此时Element被标记为“active”,然后在屏幕上显示。
3、RenderObject
渲染树中的一个对象,通过RenderObjectToWidgetAdapter将其和Element联系起来。渲染树的根是RenderView,他有一个唯一的child,是RenderBox类型。在绘制阶段,将RenderObject生成对应的Layer tree,再将其生成Scene,交给GPU绘制。
总结
三者之间的基本关系就是:Element持有Widget对象,在Element的mount阶段,通过Widget对象创建RenderObject对象,这个对象被Element持有。所以Element持有Widget和RenderObject对象。
Element管理着Widget生命周期,在生命周期不同阶段,处理RenderObject不同的渲染绘制任务。
4、启动
首先从main.dart的main方法开始运行:
void main() {
runApp(MyApp());
}
runApp方法是在一个binding.dart文件里面:
packages\flutter\lib\src\widgets\binding.dart
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
4.1 WidgetsFlutterBinding
packages\flutter\lib\src\widgets\binding.dart
WidgetsFlutterBinding类调用静态初始化方法,执行初始化操作:
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
with关键字类似于java里面的implement关键字,可以初始化及调用with后面类的方法。如果对于这个关键字比较陌生的话,可以写下面的demo代码验证一下,看看初始化顺序是怎么样的:
abstract class Test1{
Test1(){
print("parent class");
init();
}
void init(){
print("class init");
}
}
mixin Demo1 on Test1{
void init(){
print("demo1 init");
super.init();
print("demo1 init done");
}
}
mixin Demo2 on Test1,Demo1 {
void init(){
print("demo2 init");
super.init();
print("demo2 init done");
}
}
class Test2 extends Test1 with Demo1,Demo2{
Test2(){
print("child class");
}
static void test(){
Test2();
}
}
void main() {
Test2.test();
}
parent class
demo2 init
demo1 init
class init
demo1 init done
demo2 init done
child class
透过demo我们可以知道,调用顺序是先调用父类构造函数,然后with后面的类,从后往前调用,但是因为在每个binding类的initInstances方法中,都先调用了super.initInstances方法,所以实际上先执行前面的binding类代码。先看看BindingBase的构造函数:
packages\flutter\lib\src\foundation\binding.dart
BindingBase() {
initInstances();
}
到这里开始执行with从前到后binding的initInstances方法。
4.2 GestureBinding
绑定手势子系统,当一个点按下事件从window传递过来之后,被其拦截,由GestureBinding决定在哪一个节点生效。
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onPointerDataPacket = _handlePointerDataPacket;
}
获取window窗口的onPointerDataPacket方法。
4.3 ServicesBinding
监听系统消息,并通过BinaryMessenger转发。
@override
void initInstances() {
super.initInstances();
_instance = this;
_defaultBinaryMessenger = createBinaryMessenger();
window
..onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
initLicenses();
SystemChannels.system.setMessageHandler(handleSystemMessage);
}
通过createBinaryMessenger方法创建了一个默认的消息传递者。
4.4 SchedulerBinding
调度管理。调度分为几个阶段,分别是:
- 没有frame需要处理的时候,处于Idle。
- transientCallbacks,暂时的回调,比如更新RenderObject状态到animate。
- midFrameMicrotasks,中间帧微服务,比如正在处理暂时回调任务的时候。
- persistentCallbacks,持续性回调,比如layer在创建,布局,绘制阶段。
- postFrameCallbacks,清理,并准备下一帧。
@override
void initInstances() {
super.initInstances();
_instance = this;
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
readInitialLifecycleStateFromNativeWindow();
if (!kReleaseMode) {
int frameNumber = 0;
addTimingsCallback((List<FrameTiming> timings) {
for (FrameTiming frameTiming in timings) {
frameNumber += 1;
_profileFramePostEvent(frameNumber, frameTiming);
}
});
}
}
4.5 PaintingBinding
绑定了绘制库。
hook了缓存清理逻辑,用于清理图片缓存。
@override
void initInstances() {
super.initInstances();
_instance = this;
_imageCache = createImageCache();
if (shaderWarmUp != null) {
shaderWarmUp.execute();
}
}
初始化方法中创建了图片缓存对象,设置默认图片缓存大小。
shaderWarmUp其实是一个着色器预处理。在正式运行app之前,先生成一个着色器ShaderWarmUp,绘制一个场景(Scene)到里面,并缓存起来。当app里面有复杂的场景需要着色时,可以减少动画或交互时的卡顿。
着色预热操作是在GPU线程里面同步操作的,意味着,app第一帧的渲染必须等到该操作完成之后才能继续。
4.6 SemanticsBinding
Semantics是语义的意思。这个类将语义层(semantics layer)与flutter engine联系起来。
@override
void initInstances() {
super.initInstances();
_instance = this;
_accessibilityFeatures = window.accessibilityFeatures;
}
4.7 RendererBinding
packages\flutter\lib\src\rendering\binding.dart
将渲染树和Flutter engine联系起来。
@override
void initInstances() {
super.initInstances();
_instance = this;
_pipelineOwner = PipelineOwner(
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
window
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
initRenderView();
_handleSemanticsEnabledChanged();
assert(renderView != null);
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
}
看看几个关键的类。
4.7.1 PipelineOwner
packages\flutter\lib\src\rendering\object.dart
PipelineOwner管理着渲染流程。
PipelineOwner对外提供接口用于驱动渲染流程。并存储着那些请求访问渲染流程中各个阶段的状态。可以通过以下步骤来刷新渲染流程:
- flushLayout
更新任何需要重新计算布局的渲染对象。在这个阶段渲染对象的大小和布局都被计算好了。在此阶段,渲染对象的绘制和合成状态被置成dirty。
- flushCompositingBits
渲染对象的复合bit被设置成dirty状态之后会在这个阶段更新,并且每一个渲染对象都可以知道自己的子对象是否需要被复合。这个信息在绘制阶段执行裁剪的时候会起到作用。
- flushPaint
访问那些需要被绘制的渲染对象。在这个阶段,这些渲染对象有机会记录绘制命令到PictureLayer,以及组建其他复合Layer。
- flushSemantics
最后,如果启用了语义,该阶段将编译渲染对象的语义。 该语义信息由辅助技术可改善渲染树的可访问性。
4.7.2 RenderView
接下来会执行initRenderView方法,创建一个RenderView对象,他继承自RenderObject类,是整个渲染树的根。
void initRenderView() {
renderView = RenderView(configuration: createViewConfiguration(), window: window);
renderView.prepareInitialFrame();
}
接下来RenderView的对象还调用了prepareInitialFrame方法,如下:
packages\flutter\lib\src\rendering\view.dart
void prepareInitialFrame() {
scheduleInitialLayout();
scheduleInitialPaint(_updateMatricesAndCreateNewRootLayer());
}
- scheduleInitialLayout方法:
packages\flutter\lib\src\rendering\object.dart
void scheduleInitialLayout() {
_relayoutBoundary = this;
owner._nodesNeedingLayout.add(this);
}
这个方法属于RenderObject类,由此我们看到RenderView实际调用的是父类的方法,而这个owner就是我们在initInstances方法中初始化的PipelineOwner类的对象。
_nodesNeedingLayout是一个RenderObject对象的List,全局已经初始化了,在这里先将RenderView对象添加进去,作为根。
- _updateMatricesAndCreateNewRootLayer方法
在调用scheduleInitialPaint方法之前先调用_updateMatricesAndCreateNewRootLayer新建一个Layer对象:
packages\flutter\lib\src\rendering\view.dart
Layer _updateMatricesAndCreateNewRootLayer() {
_rootTransform = configuration.toMatrix();
final ContainerLayer rootLayer = TransformLayer(transform: _rootTransform);
rootLayer.attach(this);
return rootLayer;
}
ContainerLayer其实是一个复合的Layer,可以包含很多子Layer。另外Layer继承自AbstractNode。
- scheduleInitialPaint方法:
packages\flutter\lib\src\rendering\object.dart
void scheduleInitialPaint(ContainerLayer rootLayer) {
_layer = rootLayer;
owner._nodesNeedingPaint.add(this);
}
_nodesNeedingPaint是一个RenderObject对象的List,全局已经初始化了,在这里先将一个RenderView对象添加进去,另外可以看到RenderObject持有一个Layer对象。
4.7.3 addPersistentFrameCallback方法
回到RendererBinding的initInstances方法中,addPersistentFrameCallback方法添加回调,回调方法是_handlePersistentFrameCallback。
addPersistentFrameCallback方法则是把这个回调放到List中存起来,在SchedulerBinding的_persistentCallbacks阶段集中调用:
final List<FrameCallback> _persistentCallbacks = <FrameCallback>[];
void addPersistentFrameCallback(FrameCallback callback) {
_persistentCallbacks.add(callback);
}
_handlePersistentFrameCallback方法里面调用的就是drawFrame方法。
4.8 WidgetsBinding
packages\flutter\lib\src\widgets\binding.dart
将widget layer与flutter engine融合在一起。
initInstances方法:
packages\flutter\lib\src\widgets\binding.dart
void initInstances() {
super.initInstances();
_buildOwner = BuildOwner();
buildOwner.onBuildScheduled = _handleBuildScheduled;
}
BuildOwner类管理着widget的框架,比如跟踪哪些widget需要重建,在全局处理应用于widget树的任务,比如开发者在调试时启动热加载,就会组织那些渲染树中不活跃的列表元素,并触发重组指令。
网友评论