Flutter面试总结

一、请简单介绍下Flutter框架,以及它的优缺点?

Flutter是谷歌推出的一套开源跨平台UI框架,可以快速的在安卓和iOS和Web平台上构建高质量的原生用户界面。同时,Flutter还是谷歌新研发的Fuchsia操作系统的默认开发套件。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。Flutter采用现代响应式框架构建,其中心思想是使用组件来构建应用的UI。当组件的状态发生改变时,组件会重构它的描述,Flutter会对比之前的描述,以确定底层渲染树从当前状态转换到下一个状态所需要的最小更改。

优点:

  • 热重载:编辑器保存并重载,模拟器立马就可以看到效果,相比原生冗长的编译过程强很多。
  • 一切皆为Widget的理念,对于Flutter来说,手机应用里的所有东西都是Widget,通过可组合的空间集合、丰富的动画库以及分层课扩展的架构实现了富有感染力的灵活界面设计。
  • 借助可移植的GPU加速的渲染引擎以及高性能的代码运行时以达到垮平台设备的高质量用户体验。简单来说:最终结果就是利用Flutter构建的应用在运行效率上和原生应用差不多。

缺点:

  • 不支持热更新;
  • 三方库有限,需要自己造轮子。
  • Dart语言编写,增加了学习难度,并且学习了Dart之后无其他用处。

二、介绍下Flutter的理念架构

截屏2020-12-03 下午2.14.47.png

由上图可知,Flutter框架自下而上分为Embedder(嵌入器)、Engine(引擎)、Framework三层。

  • 其中Embedder是操作系统适配层,实现了渲染Surface设置,线程设置,以及平台插件等相关特性的适配。
  • Engine层负责图形绘制、文字排版和提供Dart运行时,Engine层具有独立虚拟机,正是由于它的存在,Flutter程序才能运行在不同的平台上,实现跨平台运行。
  • Franework层则是使用Dart编写的一套基础视图库,包含了动画、图形绘制和手势识别等功能,是使用频率最高的一层。

三、介绍下Flutter的Framework层和Engine层,以及它们的作用

Flutter的Framework层是用Dart编写的框架(SDK),它实现了一套基础库,包含Material (安卓风格UI) 和Cupertino (iOS风格UI)的UI界面,下面是通过Widgets(组件),之后是一些动画、绘制、渲染、手势等。这个纯Dart实现的SDK被封装为了一个叫做dart:ui的Dart库。我们在使用Flutter写App的时候,直接导入这个库即可使用组件等功能。

Flutter的Engine层是Skia 2D的绘制引擎库,其前身是一个向量绘图软件,Chrome和安卓均采用Skia作为绘图引擎。Skia提供了非常友好的API,并且在图形转换、文字渲染、位图渲染方面都提供了友好的、高效的表现。Skia是垮平台的,所以可以被嵌入到Flutter的IOS SDK中,而不用去研究iOS闭源的Core Graphics/ Core Animation。安卓自带了Skia,所以Flutter 安卓 SDK要比iOS SDK小很多。

四、介绍下Widget、State、Context概念

  • Widget:在Flutter中,几乎所有东西都是Widget。将一个Widget想象为一个可视化的组件(或者与应用可视化方面交互的组件),当你需要构建与布局直接或间接相关的任何内容时,你正在使用Widget。
  • Widget树:widget以树结构进行组织。包含其他Widget的widget被称为父widget。包含在widget中的widget被称为子widget
  • Context: 仅仅是已创建的所有Widget树结构中的某个widget的位置引用。简而言之,将context作为widget树的一部分,其中context所对应的widget被添加到此树中。一个context只属于一个widget,它和widget一样是链接在一起的,并且会形成context树。
  • State:定义了StatefulWidget实例的行为,它包含了用于“交互/干预”Widget信息的行为和布局。应用于State的任何更改都会强制重建Widget

图:https://upload-images.jianshu.io/upload_images/723261-7316939df3af1b6e.png

五、简述Widget的SatelessWidget和StatefulWidget两种状态组件类

六、StatefulWidget的生命周期

Flutter的Widget分为StatelessWidget和StatefulWidget两种,其中SatelessWidget是无状态的,StatefulWidget是有状态的。我们更多的使用StatefulWidget,它的生命周期如下


截屏2020-12-03 下午3.53.56.png
  • initState():Widget初始化当前State,在当前方法中是不能获取到Context的,如果想获取可以试试Future.delayed()

  • didChangeDependencies():在initState() 后调用,State对象依赖关系发生变化的时候就会调用。(典型的场景是当系统语言Locale或应用主题改变时,Flutter framework会通知widget调用此回调。)

  • build()
    主要是用于构建Widget子树,调用时机如下:
    在调用initState()之后。
    在调用didUpdateWidget()之后。
    在调用setState()之后。
    在调用didChangeDependencies()之后。
    在State对象从树中一个位置移除后(会调用deactivate)又重新插入到树的其它位置之后。

  • reassemble()
    主要用于调试,热重载时调用,release环境下不会调用

  • didUpdateWidget: Widget状态发生变化时调用。
    Widget.canUpdate返回true则会调用此回调

  • deactivate():当State被暂时从视图树中移除时会调用这个方法,页面切换时也会调用该方法。

  • dispose():Widget销毁时调用
    从widget树中移除State对象,并不再插入此State对象时调用(一般用于释放资源)

七、简述Widgets、RenderObjects和Elements的关系

首先看一下这几个对象的含义以及作用

  • Widget:仅仅用于存储渲染所需要的信息。
  • RenderObject:负责管理布局、绘制等操作。
  • Element:才是这颗巨大的控件树的实体。

八、简述Flutter的绘制流程

截屏2020-12-04 上午9.12.24.png

Flutter只关心GPU提供视图数据,GPU的VSync信号同步到UI线程,UI线程使用Dart来构建抽象的视图结构,这份数据结构在GPU线程进行图层合成,视图数据提供给Skia引擎渲染为GPU数据,这些数据通过OpenGL或者Vulkan提供给GPU。

九、Flutter是如何与原生Android、iOS进行通信的?

Flutter通过PlatformChannel与原生进行交互,其中PlatformChannel分为三种:

  • BasicMessageChannel: 用于传递字符串和半结构化的信息。
  • MethodChannel: 用户传递方法调用(method invocation)
  • EventChannel: 用于数据流(event streams)的通信。

同时Platform Channel并非是线程安全的,详细可查看《深入理解Flutter Platform Channel》

十、简述Flutter的热重载

Flutter的热重载是基于JIT编译模式的代码增量同步。由于JIT属于动态编译,能够将Dart代码编译生成中间代码,让Dart VM在运行的时解释执行,因此可以通过动态更新中间代码实现增量同步。

热重载的流程可以分为5步,包括:扫描工程改动、增量编译、推送更新、代码合并、Widget重建。Flutter在接收到代码变更后,并不会让App重新启动执行,而只会出发Widget树的重新绘制,因此可以保持改动前的状态,大大缩短了从代码修改到看到修改产生的变化之间所需要的时间。

另一方面,由于涉及到状态的保存与恢复,涉及状态兼容与状态初始化的场景,热重载是无法支持的,比如改动前后Widget状态无法兼容、全局变量与静态属性的更改、main方法里的更改、initSate方法的更改、枚举和泛型的更改等。

可以发现,热重载提供了调试UI的效率,非常适合写界面样式这样反复查看修改效果的场景,但是由于其状态保存的机制有限,热重载本身也有一些无法支持的边界。

更多资料参考Flutter的Hot Reload是如何实现的

十一、Stateless Widget和Stateful Widget区别

StatelessWidget用于不需要维护状态的场景,StatefulWidget用于状态会发生变化的场景,他们都继承自Widget

StatelessWidget,重写了createElement() 方法,StatelessElement间接继承自Element类,

@override
StatelessElement createElement() => new StatelessElement(this);

StatefulWidget也是重写了createElement()方法,不通的是返回的Elment对象并不相同,另StatefulWidget类中添加了一个新的接口createState().

  • StatefulElement间接继承自Element类,与StatefulWidget相对应(作为其配置数据)。StatefulElement中可能会多次调用createState() 来创建状态(State)对象。

  • createState() 用于创建和StatefulWidget相关的状态,它在
    StatefulWidget的生命周期中可能被多次调用。例如,当一个StatefulWidget同时插入到widget树的多个位置,Flutter framework就会调用该方法为每一个位置生成一个独立的State实例,其实,本质上就是一个StatefulElement对应一个State实例。

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);

  @override
  StatefulElement createElement() => new StatefulElement(this);

  @protected
  State createState();
}

https://blog.csdn.net/sinat_17775997/article/details/106520786

十二、Widget唯一标识Key有哪几种?

在flutter中,每个widget都是被唯一标识的。这个唯一标识在build或rendering阶段由框架定义。该标识对应于可选的Key参数,如果省略,Flutter将会自动生成一个。
在flutter中,主要有4中类型的Key:GlobalKey(确保生成的Key在整个应用中唯一,是很昂贵的,允许element在树周围移动或变更父节点而不丢失状态)、LocalKey、UniqueKey、ObjectKey。

十三、什么是Navigator? MaterialApp做了什么?

Navigator是Flutter中负责管理维护页面堆栈的导航器。MaterialApp在需要的时候,会自动为我们创建Navigator.
Navigator.of(context),会使用context来向上遍历Element树,找到MaterialApp提供的_NavigatorState再调用其push/pop方法完成导航操作。

十四、Flutter main future mirotask 的执行顺序?

普通代码都是同步执行的。结束后会开始检查mirotask中是否有任务,若有则执行,执行完毕继续检查mirotask,直到microtask队列为空。最后会去执行event队列(future)。

十五、await for 如何使用?

await for 是不断获取stream流中的数据,然后执行循环体中的操作。它一般用在直到stream什么时候完成,并且必须等待传递完成之后才能使用,不然就会一直阻塞。

Stream stream = new Stream.fromIterable(['不开心', '面试', '没', '过']);
main() async{
  print('上午被开水烫了脚');
  await for(String s in stream){
    print(s);
  }
  print('晚上还没吃饭');
}

你可能感兴趣的:(Flutter面试总结)