2024年最全字节跳动技术整理,一文秒懂,Flutter 跨平台演进及架构(2),2024年最新flutter 页面跳转动画

总结:

各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。

  • BAT大厂面试题、独家面试工具包,

  • 资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

2017年5月Google I/O大会正式对外公布Flutter,到2018年12月发布Flutter1.0,引发全球大量的开发者和企业开始研究Flutter。StackOverflow 2019年的全球开发者文件调查中,Flutter被评选为最受开发者欢迎的框架之一,超过了TensorFlow和Node.js。

19956127-a06149b3030b6854.png

到目前,全球越来越多的公司已经在大家耳熟能详的知名APP中使用Flutter技术并落地,尤其国内知名互联网公司对Flutter投入度很大,社区也是非常活跃。

19956127-016816a9d0d1e12f.png

8. Flutter未来趋势

目前Flutter主要在移动端Android/iOS双端跨端,Flutter 的愿景是成为一个多端运行的 UI 框架,能够支持不仅仅是移动端,还包括Web、桌面、甚至嵌入式设备。在2019 Google I/O 开发者大会上推出的使用 Flutter 开发 Web 应用的框架,同年9月发布Flutter 1.9,并将Flutter web合入Flutter主仓库。

19956127-4a04fb11c708ebc8.png

从架构图看,Flutter采用同一个Dart Framework层来统一Flutter C++引擎和Web引擎,最终可以运行在Android,iOS,Browser上,从Flutter引擎代码不难看出Flutter也是支持Fuchsia操作系统。

Fuchsia是Google内部正在开发的一款新的操作系统,采用Flutter作为系统默认的UI框架,也就是说Flutter天然支持Fuchsia,这无疑让Flutter在众多的跨平台方案更有优势。

从Fuchsia技术架构来看,内核层zircon的基础LK是专为嵌入式应用中小型系统设计的内核,代码简洁,适合嵌入式设备和高性能设备,比如IOT、移动可穿戴设备等,目前这些领域还没有标准化级别的垄断者。以及在框架层中有着语音交互、云端以及智能化等模块,由此笔者揣测未来Fuchsia率先应用在音控等智能嵌入式设备。

19956127-5dfc8146538bfd70.png

目前大家普遍比较看好的未来两个技术就是5G和IoT时代。对于5G的需求,很大程度上是因为移动互联网发展到“IoT时代”的阶段。这个发展阶段,全球上网设备的数量可能会达到500亿个。随着5G+IOT时代的到来,现在大家比较关注的Flutter包大小也同样不再是一个问题,或许Flutter技术的生命期比客户端更长,或许Fuchsia正在驰骋IOT疆场,你所掌握的Flutter技术栈可以无缝迁移,一次弯道超车的机会。

到此,介绍完跨平台技术演进以及Flutter的优势。看到这,相信你可能对Flutter技术有一定兴趣,为了能让大家快速了解Flutter内部原理而不枯燥,Gityuan通过一系列图来帮大家从整体架构来快速理解Flutter。

二、Flutter引擎架构


1. Flutter技术架构

先来看看Flutter整体的技术架构,分为四层,从上之下依次是Dart APP,Dart Framework, C++ Engine,Platform。

19956127-fdae9989a01cf32b.png

Flutter架构最核心的便是Framework(框架)和Engine(引擎):

  • Flutter Framework层:用Dart编写,封装整个Flutter架构的核心功能,包括Widget、动画、绘制、手势等功能,有Material(Android风格UI)和Cupertino(iOS风格)的UI界面, 可构建Widget控件以及实现UI布局。

  • Flutter Engine层:用C++编写,用于高质量移动应用的轻量级运行时环境,实现了Flutter的核心库,包括Dart虚拟机、动画和图形、文字渲染、通信通道、事件通知、插件架构等。引擎渲染采用的是2D图形渲染库Skia,虚拟机采用的是面向对象语言Dart VM,并将它们托管到Flutter的嵌入层。shell实现了平台相关的代码,比如跟屏幕键盘IME和系统应用生命周期事件的交互。不同平台有不同的shell,比如Android和iOS的shell。

2. Flutter编译产物

看完Flutter内部架构,或许你好奇,Flutter不用Android/iOS的本地语言技术开发,Dart编写完的代码如何让不同系统可以识别,最终编译后得到的产物是什么呢?

19956127-79ad3332a3e509b6.png

Flutter产物分为Dart业务代码和Engine代码各自生成的产物,图中的Dart Code包含开发者编写的业务代码,Engine Code是引擎代码,如果并没有定制化引擎,则无需重新编译引擎代码。

一份Dart代码,可编译生成双端产物,实现跨平台的能力。经过编译工具处理后可生成双端产物,图中便是release模式的编译产物,Android产物是由vm、isolate各自的指令段和数据段以及flutter.jar组成的app.apk,iOS产物是由App.framework和Flutter.framework组成的Runner.app。

这个过程涉及frontend_server、gen_snapshot、xcrun、ninja编译工具。frontend_server前端编译器会进行词法分析、语法分析以及相关全局转换等工作,将dart代码转换为AST(抽象语法树),并生成app.dill格式的dart kernel。gen_snapshot经过CHA、内联等一系列执行流的优化,根据中间代码生成优化后的FlowGraph对象,再转换为具体相应系统架构(arm/arm64等)的二进制指令。

3. Flutter引擎启动

既然了解了Flutter的编译产物,那你或许又好奇,Flutter这台引擎如何发动的,怎么跟Native衔接呢?

19956127-f8cd15af3a1ab04b.png

这里以Android为例,熟悉Android的开发者,应该都了解APP启动过程,会执行Application和Activity的onCreate()方法,FlutterApplication和FlutterActivity的onCreate()方法正是连接Native和Flutter的枢纽。

  • FlutterApplication.java的onCreate过程主要完成初始化配置、加载引擎libflutter.so、注册JNI方法;

  • FlutterActivity.java的onCreate过程,通过FlutterJNI的AttachJNI()方法来初始化引擎Engine、Dart虚拟机、Isolate、taskRunner等对象。再经过层层处理最终调用main.dart中main()方法,执行runApp(Widget app)来处理整个Dart业务代码。

Flutter引擎启动中会创建有4个TaskRunner以及创建虚拟机,分别来看看它们的工作原理。

4. TaskRunner工作原理

Flutter引擎启动过程,会创建UI/GPU/IO这3个线程,会为这些线程依次创建MessageLoop对象,启动后处于epoll_wait等待状态。对于Flutter的消息机制跟Android原生的消息机制有很多相似之处,都有消息(或者任务)、消息队列(或任务队列)以及Looper;有一点不同的是Android有一个Handler类,用于发送消息以及执行回调方法,相对应Flutter中有着相近功能的便是TaskRunner。

19956127-adee87aea350a9a0.png

上图是从源码中提炼而来的任务处理流程,比官方流程图更容易理解一些复杂流程的时序问题,后续会专门讲解个中原由。Flutter的任务队列处理机制跟Android的消息队列处理相通,只不过Flutter分为Task和MicroTask两种类型,引擎和Dart虚拟机的事件以及Future都属于Task,Dart层执行scheduleMicrotask()所产生的属于Microtask。

每次Flutter引擎在消费任务时调用FlushTasks()方法,遍历整个延迟任务队列delayed_tasks_,将已到期的任务加入task队列,然后开始处理任务。

  • Step 1: 检查task,当task队列不为空,先执行一个task;

  • Step 2: 检查microTask,当microTask不为空,则执行microTask;不断循环Step 2 直到microTask队列为空,再回到执行Step 1;

可简单理解为先处理完所有的Microtask,然后再处理Task。因为scheduleMicrotask()方法的调用自身就处于一个Task,执行完当前的task,也就意味着马上执行该Microtask。

了解了其工作机制,再来看看这4个Task Runner的具体工作内容。

  • Platform Task Runner:运行在Android或者iOS的主线程,尽管阻塞该线程并不会影响Flutter渲染管道,平台线程建议不要执行耗时操作;否则可能触发watchdog来结束该应用。比如Android、iOS都是使用平台线程来传递用户输入事件,一旦平台线程被阻塞则会引起手势事件丢失。

  • UI Task Runner: 运行在ui线程,比如1.ui,用于引擎执行root isolate中的所有Dart代码,执行渲染与处理Vsync信号,将widget转换生成Layer Tree。除了渲染之外,还有处理Native Plugins消息、Timers、Microtasks等工作;

  • GPU Task Runner:运行在gpu线程,比如1.gpu,用于将Layer Tree转换为具体GPU指令,执行设备GPU相关的skia调用,转换相应平台的绘制方式,比如OpenGL, vulkan, metal等。每一帧的绘制需要UI Runner和GPU Runner配合完成,任何一个环节延迟都可能导致掉帧;

  • IO Task Runner:运行在io线程,比如1.io,前3个Task Runner都不允许执行耗时操作,该Runner用于将图片从磁盘读取出来,解压转换为GPU可识别的格式后,再上传给GPU线程。为了能访问GPU,IO Runner跟GPU Runner的Context在同一个ShareGroup。比如ui.image通过异步调用让IO Runner来异步加载图片,该线程不能执行其他耗时操作,否则可能会影响图片加载的性能。

5. Dart虚拟机工作

Flutter引擎启动会创建Dart虚拟机以及Root Isolate。DartVM自身也拥有自己的Isolate,完全由虚拟机自己管理的,Flutter引擎也无法直接访问。Dart的UI相关操作,是由Root Isolate通过Dart的C++调用,或者是发送消息通知的方式,将UI渲染相关的任务提交到UIRunner执行,这样就可以跟Flutter引擎相关模块进行交互。

何为Isolate,从字面上理解是“隔离”,isolate之间是逻辑隔离的。Isolate中的代码也是按顺序执行,因为Dart没有共享内存的并发,没有竞争的可能性,故不需要加锁,也没有死锁风险。对于Dart程序的并发则需要依赖多个isolate来实现。

19956127-7c028467f3827d76.png

图解:

  • isolate堆是运该isolate中代码分配的所有对象的GC管理的内存存储;

  • vm isolate是一个伪isolate,里面包含不可变对象,比如null,true,false;

  • isolate堆能引用vm isolate堆中的对象,但vm isolate不能引用isolate堆;

  • isolate彼此之间不能相互引用;

  • 每个isolate都有一个执行dart代码的Mutator thread,一个处理虚拟机内部任务(比如GC, JIT等)的helper thread; 可见,isolate是拥有内存堆和控制线程,虚拟机中可以有很多isolate,但彼此之间内存不共享,无法直接访问,只能通过dart特有的Port端口通信;isolate除了拥有一个mutator控制线程,还有一些其他辅助线程,比如后台JIT编译线程、GC清理/并发标记线程;

6. Widget架构概览

Flutter引擎启动后执行Dart业务,是通过runApp(Widget app)方法,那Widget又是什么呢?

19956127-623481d275339c4b.png

Widget是所有Flutter应用程序的基石,Widget可以是一个按钮,一种字体或者颜色,一个布局属性等,在Flutter的UI世界可谓是“万物皆Widget”。常见的Widget子类为StatelessWidget(无状态)和StatefulWidget(有状态);

  • StatelessWidget:内部没有保存状态,UI界面创建后不会发生改变;

  • StatefulWidget:内部有保存状态,当状态发生改变,调用setState()方法会触发StatefulWidget的UI发生更新,对于自定义继承自StatefulWidget的子类,必须要重写createState()方法。

三棵树

19956127-41bcb8fb44b88708.png

图解:

  • Widget是为Element描述需要的配置, 负责创建Element,决定Element是否需要更新。Flutter Framework通过差分算法比对Widget树前后的变化,决定Element的State是否改变。当重建Widget树后并未发生改变, 则Element不会触发重绘,则就是Widget树的重建并不一定会触发Element树的重建。

  • Element表示Widget配置树的特定位置的一个实例,同时持有Widget和RenderObject,负责管理Widget配置和RenderObject渲染。Element状态由Flutter Framework管理, 开发人员只需更改Widget即可。

  • RenderObject表示渲染树的一个对象,负责真正的渲染工作,比如测量大小、位置、绘制等都由RenderObject完成。

可见,开发者通过Widget配置,Framework通过比对Widget配置来更新Element,最后调度RenderObject Tree完成布局排列和绘制。

7. 渲染原理

Dart的UI采用Widget来实现,最终转换为RenderObject,那界面又是如何渲染的呢?

19956127-0fd36bf5c7d7a0e8.png

渲染过程,UI线程完成布局、绘制操作,生成Layer Tree;GPU线程执行合成并光栅化后交给GPU来处理,其中几个关键步骤:

  • Animate: 遍历_transientCallbacks,执行动画回调方法;

  • Build: 对于dirty的元素会执行build构造,没有dirty元素则不会执行,对应于buildScope()

  • Layout: 计算渲染对象的大小和位置,对应于flushLayout(),这个过程可能会嵌套再调用build操作;

  • Compositing bits: 更新具有脏合成位的任何渲染对象, 对应于flushCompositingBits();

  • Paint: 将绘制命令记录到Layer, 对应于flushPaint();

  • Compositing: 将Compositing bits发送给GPU, 对应于compositeFrame();

GPU线程通过skia向GPU硬件绘制一帧的数据,GPU将帧信息保存到FrameBuffer里面,然后视频控制器会根据VSync信号从FrameBuffer取帧数据传递给显示器,从而显示出最终的画面。

8. Platform Channels

Flutter框架提供了UI的控件支持,对于APP除了UI还有其他依赖于Native平台的支持,比如调用Camera的功能,该怎么办呢?为此,Flutter通过提供Platform Channel的功能,使得Dart代码具备与Native交互的能力。

19956127-b01f1506c7585eec.png

Platform Channel用于Flutter与Native之间的消息传递,整个过程的消息与响应是异步执行,不会阻塞用户界面。Flutter引擎框架已完成桥接的通道,这样开发者只需在Native层编写定制的Android/iOS代码,即可在Dart代码中直接调用,这也就是Flutter Plugin插件的一种形式。

三、Flutter源码解读


笔者(Gityuan)之前一直从事于Android操作系统底层研发工作,今年刚接触Flutter,Flutter作为一门全新的跨平台技术框架,不断深究会发现这是一个小型系统,涉及到的技术很广:

  • 编译技术如何将dart代码转换为AST(抽象语法树),如何汇编转换为机器码,打包产物是什么?

  • Flutter这台引擎如何发动的,怎么跟Native原生系统衔接运行,如何识别产物并加载到内存?

  • 引擎启动后,TaskRunner如何分发任务,跟原生系统消息机制有什么关系?

  • Dart虚拟机如何管理内存,跟isolate又有什么关系?

  • 开发者编写的Widget控件如何渲染到屏幕上?

  • Flutter如何通过plugin支持移动设备提供的服务?

这些疑问在前面都逐一简要解答,如果仅仅是用Flutter做业务开发,并不需要掌握这么深度技术,不过,知其然知其所以然,能让你游刃有余。

启动篇
通信篇
渲染篇
最后

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

有开发经验的Android程序员们学习。

[外链图片转存中…(img-4sOM07t2-1715896123355)]

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值