如何实现一个跨平台UI框架-以Flutter为例(序)

134 阅读4分钟

22年毕业以来,工作上一直使用Flutter来开发多端app,虽然对Flutter的实现很感兴趣,但一直以来只是浅显地停留在使用widget搭建UI。最多也就是对三棵树的生成更新有一些了解。更细一点,对于布局的生成渲染,对于引擎的运行,以及手势、滑动的抽象等等内容,都没有去深入学习。

最近愈发觉得,就这样下去,离自己的初心越来越远,成为了最不想成为的UI编写工。而对于性能、滑动流畅度、内存占用,底层渲染bug排查等等这些真正有价值的能力,远远没有掌握。虽然一直想深入底层学习,但一旦面对浩如烟海的源码,却很容易就不知道怎么下手,然后业务稍微忙一点,就停下来了,最后就是几年过去,还是在原地踏步。不了解底层很容易碰壁,比如:突然发现Flutter在写一些渐变颜色背景时很卡,滑动不流畅,如果对其引擎层的渲染不了解,光看一下帧率图和官方的dev工具,根本看不出来任何原因。

长期处于不了解底层的状态,很容易遇到问题但完全无法解决。在刚开始学习C语言时,我们定义变量、函数,分配内存,一切都是处于比较清晰的可掌控的范围,我们很清楚代码从main函数开始运行,一步步,走完全流程,任何计算机语言的学习都是这样。但在学习App开发时,一切都变了,比如学习Android时,首先官方教程告诉我们的是,定义MainActivity,继承官方的类,然后再重写onCreate这样的方法,至于main函数?app启动的入口完全被Framework隐藏起来了。在这样的逻辑下,不需要了解底层,仅仅是实现一些回调函数,我们就从掌控程序全流程的角色变成了根据指南完成工作的角色。这种角色的转变极大地限制了我们的成长,并使得我们很难再有那种第一次看到编译的代码按照自己要求执行时的成就感。

按照还原论的角度,cpu只是不断取指令执行,指令是有限种类的,计算机科学的发展就是向上一层层包装,汇编、操作系统、应用层Framework、应用本身......但很多时候这种包装性不是那么完备,需要我们对下一层有所了解才能更好地开发上一层。对于App开发而言,至少得对Framework很熟悉才能理解自己的代码如何运行的。

说了这么多,明明Framework这么重要,但大部分人包括我,其实都在门口徘徊,更别说熟悉了。看了很多源码解析的书或者文章,最后发现还是一知半解,最后就自然而然无限期地搁置了。我分析了一下原因:一是Framework本身的庞大、复杂的封装让人难以切入,二是缺乏输出,仅仅是看了一下,缺乏把自己学到的东西输出成文章,与大家讨论。

对于Framework的学习方法,我打算换个思路。以往很多技术文章,都是把Framework的某个类某个函数贴出来,告诉大家这个函数干了什么功能,然后另一个函数又是做什么的。最后把类的继承关系摆一摆,但读者真的能通过这些学会某个模块的结构以及作用吗?恐怕很难吧。不如换个角度,想一想,代码总是人写的,是为了实现某个具体的功能来写的,对于一些复杂的模块,我通过读这些代码来理解功能,就像是从反编译的汇编猜源码的功能一样,恐怕这条路本身就是不太可行的。正确的方向可能是这样:假设我要解决这个功能,我应该怎么写?在写的过程中去参照Framework作者的代码,在不断对比中学习,最后达到实现功能的目的。在这个过程中,我是主动地参与者,而不是一个被动的代码阅读器,由于需要不断输出,知识会在大脑的神经网络里留下更深的连接。同时,实现功能成为了一个标识我们掌握程度的可靠指标,在被动阅读的过程中,我们是很难知道自己对源码的理解程度。

于是乎,就有了这篇文章,我打算逐渐地实现一个简单的UI框架,通过这个工作,来达到学习Flutter源码的目的,在实现的过程中,我会大量参照源码,并从实现功能的角度去分析Flutter源码。对于上文提到的第二个问题——缺乏输出与交流,我会把实现的步骤写成文章,记录下来,与大家多交流。