Flutter入口runApp源码分析

// WidgetsFlutterBinding可以理解为是widget框架和Flutter引擎的桥梁

class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {

static WidgetsBinding ensureInitialized() {

if (WidgetsBinding.instance == null)

WidgetsFlutterBinding();

return WidgetsBinding.instance!;

}

}

WidgetsFlutterBinding类继承自BindingBase并且混入[mixin]了很多其他Binding类,看名称都是绑定各种不同的功能;

BindingBase,上面的各个mixin Binding类都是继承自它,各个mixin类都重写了initInstances()方法,并且调用了super.initInstances(),所以他们所有的initInstans()方法都会被串行顺序执行。如果对mixin机制不是很理解可以先看看”小白都能看懂的关于Mixins机制的理解“。最终FlutterWidgetBinding()初始化的逻辑为:

在这里插入图片描述

WidgetsFlutterBinding经过mixin依赖,实现了所有的Binding类的功能,下面逐一大概介绍一下每个Binding的作用:

  1. GestureBinding:提供了window.onPointerDataPacket的回调,绑定Fragmework子系统,是Framework事件模型与底层事件的绑定入口。
  1. ServicesBinding:提供了window.onPlatformMessage回调,用于绑定平台消息通道(messagechannel),主要处理原生和Flutter之间的通信。
  1. SchedulerBinding:提供了window.onBeginFrame和window.onDrawFrame回调,监听刷新事件,绑定Framework绘制调度子系统
  1. PaintingBinding:绑定绘制库,主要用于处理图片缓存。
  1. SematicsBinding:语义化层与Flutter engine的桥梁,主要是辅助功能的底层支持。
  1. RenderBinding:提供了window.onMetricsChange、window.onTextScaleFactorChanged等回调。它是渲染树与Flutter engine的桥梁。
  1. WidgetsBinding:提供了window.onLocaleChanged,onBuildScheduled等回调。它是Flutter widget层与engine的桥梁。

很明显,可以看到Window类提供了各种平台的回调方法,正是我们Flutter Framework连接宿主操作系统的接口。我们来大致看下源码:

class Window {

// 当前设备的DPI,即一个逻辑像素显示多少物理像素,数字越大,显示效果就越精细保真。

// DPI是设备屏幕的固件属性,如Nexus 6的屏幕DPI为3.5

double get devicePixelRatio => _devicePixelRatio;

// Flutter UI绘制区域的大小

Size get physicalSize => _physicalSize;

// 当前系统默认的语言Locale

Locale get locale;

// 当前系统字体缩放比例。

double get textScaleFactor => _textScaleFactor;

// 当绘制区域大小改变回调

VoidCallback get onMetricsChanged => _onMetricsChanged;

// Locale发生变化回调

VoidCallback get onLocaleChanged => _onLocaleChanged;

// 系统字体缩放变化回调

VoidCallback get onTextScaleFactorChanged => _onTextScaleFactorChanged;

// 绘制前回调,一般会受显示器的垂直同步信号VSync驱动,当屏幕刷新时就会被调用

FrameCallback get onBeginFrame => _onBeginFrame;

// 绘制回调

VoidCallback get onDrawFrame => _onDrawFrame;

// 点击或指针事件回调

PointerDataPacketCallback get onPointerDataPacket => _onPointerDataPacket;

// 调度Frame,该方法执行后,onBeginFrame和onDrawFrame将紧接着会在合适时机被调用,

// 此方法会直接调用Flutter engine的Window_scheduleFrame方法

void scheduleFrame() native ‘Window_scheduleFrame’;

// 更新应用在GPU上的渲染,此方法会直接调用Flutter engine的Window_render方法

void render(Scene scene) native ‘Window_render’;

// 发送平台消息

void sendPlatformMessage(String name,

ByteData data,

PlatformMessageResponseCallback callback) ;

// 平台通道消息处理回调

PlatformMessageCallback get onPlatformMessage => _onPlatformMessage;

… //其它属性及回调

}

Window类包含了当前设备和系统的一些信息以及Flutter Engine的一些回调。通过这些Binding 监听Window对象的一些事件,然后将这些事件按照Framework的模型包装,抽象再分发。

2、scheduleAttachRootWidget

WidgetsFlutterBinding初始化之后,接着会调用WidgetsBinding.attachRootWidget方法,该方法负责将根Widget添加到RenderView上,

void attachRootWidget(Widget rootWidget) {

_readyToProduceFrames = true;

_renderViewElement = RenderObjectToWidgetAdapter(

container: renderView,

debugShortDescription: ‘[root]’,

child: rootWidget,

).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement?);

}

注意:

代码中的renderView是一个RenderObject,它渲染树的根

renderViewElement是renderView对应的Element对象,可见该方法主要完成根widget到根RenderObject再到跟Element的整个关联过程。

再来看看attachToRenderTree源码实现:

/// Inflate this widget and actually set the resulting [RenderObject] as the

/// child of [container].

///

/// If element is null, this function will create a new element. Otherwise,

/// the given element will have an update scheduled to switch to this widget.

///

/// Used by [runApp] to bootstrap applications.

RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement? element ]) {

if (element == null) {

owner.lockState(() {

element = createElement();

assert(element != null);

element!.assignOwner(owner);

});

owner.buildScope(element!, () {

element!.mount(null, null);

});

// This is most likely the first time the framework is ready to produce

// a frame. Ensure that we are asked for one.

SchedulerBinding.instance!.ensureVisualUpdate();

} else {

element._newWidget = this;

element.markNeedsBuild();

}

return element!;

}

该方法负责创建根element,即:RenderObjectToWidgetElement,并且将element于widget进行关联,即创建出widget数对对应的element树。如果element已经创建过了,则将根element中关联的widget设为新的,由此可以看出element只会创建一次,后面会进行复用。那么BuildOwner是什么呢?其实它就是widget fragment的管理类,它跟踪哪些widget需要重新构建。

3、热身帧绘制

​ 组件数在构建(build)完成以后,回到runApp实现中,当attachRootWidget后,最后一行调用WidgetsFlutterBinding实例的scheduleWarmUpFrame()方法,该方法在实例SchedulerBinding中,它被调用后会立即进行一次绘制,在此次绘制结束之前,该方法会锁定事件分发,也就是说在本次绘制结束完成之前Flutter将不会响应各个事件,这可以保证在绘制过程中不会被再出发新的绘制。

scheduleWarmUpFrame()源码

void scheduleWarmUpFrame() {

if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle)

return;

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
img-c3dZSxgO-1715529336712)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值