以下主要针对往期收录的面试题进行一个分类归纳整理,方便统一回顾和参考。本篇是第九集【完结篇】~
强调一下:别问了别问了, 面试文档要的直接找作者获取。
第一篇面试题在这: Android中高级进阶开发面试题冲刺合集(一)
第二篇在这: Android中高级进阶开发面试题冲刺合集(二)
第三篇在这: Android中高级进阶开发面试题冲刺合集(三)
第四篇在这: Android中高级进阶开发面试题冲刺合集(四)
第五篇在这: Android中高级进阶开发面试题冲刺合集(五)
第六篇在这: Android中高级进阶开发面试题冲刺合集(六)
第七篇在这: Android中高级进阶开发面试题冲刺合集(七)
第八篇在这:Android中高级进阶开发面试题冲刺合集(八)【Flutter篇】
Dart相关1.Dart 当中的 「…」表示什么意思?
参考答案:
“…” 和 “.” 不同:调用..
后返回的相当于是this
,而.
返回的则是该方法返回的值;
2.Dart 的作用域是怎么样的?
参考答案:
Dart没有public
和private
等关键词,默认就是公开的,私有变量使用下划线开头;
3.dart是多线程还是单线程执行?
参考答案:
单线程执行,多线程是使用异步来执行的;
4.阻塞式调用和非阻塞式调用是怎么样的?
参考答案:
阻塞:调用结果之前,当前线程会被挂起,调用线程只有在得到结果之后才会继续执行;
非阻塞:调用执行之后,当前线程不会停止运行,只需要过一段时间来检查有没有结果返回即可;
5.事件循环是什么?
参考答案:
将需要处理的一系列事件,放在一个事件队列(Event Queue
)中,不断从事件队列中取出事件,并执行需要执行的代码块,直到事件被清空。
6.dart是值传递还是引用传递?
参考答案:
dart是值传递。我们每次调用函数,传递过去的都是对象的内存地址,而不是这个对象的复制。
7.Dart 语言有哪些重要的特性?
参考答案:
- Productive(生产力高,Dart的语法清晰明了,工具简单但功能强大)
- Fast(执行速度快,Dart提供提前优化编译,以在移动设备和Web上获得可预测的高性能和快速启动。)
- Portable(易于移植,Dart可编译成ARM和X86代码,这样Dart移动应用程序可以在iOS、Android和其他地方运行)
- Approachable(容易上手,充分吸收了高级语言特性,如果你已经知道C++,C语言,或者Java,你可以在短短几天内用Dart来开发)
- Reactive(响应式编程)
8.Dart 语言有哪些重要的概念?
参考答案:
- 在Dart中,一切都是对象,所有的对象都是继承自
Object
- Dart是强类型语言,但可以用var或
dynamic
来声明一个变量,Dart会自动推断其数据类型,dynamic
类似c# - 没有赋初值的变量都会有默认值
null
- Dart支持顶层方法,如
main
方法,可以在方法内部创建方法 - Dart支持顶层变量,也支持类变量或对象变量
- Dart没有
public
protected
private
等关键字,如果某个变量以下划线(_)开头,代表这个变量在库中是私有的
9.Dart线程模型是如何执行的?
参考答案:
Dart 是单线程模型,运行的的流程如下图。
Dart 在单线程中是以消息循环机制来运行的,包含两个任务队列,一个是“微任务队列”
microtask queue
,另一个叫做“事件队列” event queue
。 当Flutter应用启动后,消息循环机制便启动了。首先会按照先进先出的顺序逐个执行微任务队列中的任务,当所有微任务队列执行完后便开始执行事件队列中的任务,事件任务执行完毕后再去执行微任务,如此循环往复,生生不息。
10.Dart 是如何实现多任务并行的?
参考答案:
Dart 是单线程的,不存在多线程,那如何进行多任务并行的呢?其实,Dart的多线程和前端的多线程有很多的相似之处。Flutter的多线程主要依赖Dart的并发编程、异步和事件驱动机制。 简单的说,在Dart中,一个
Isolate
对象其实就是一个isolate
执行环境的引用,一般来说我们都是通过当前的isolate
去控制其他的isolate
完成彼此之间的交互,而当我们想要创建一个新的Isolate
可以使用Isolate.spawn
方法获取返回的一个新的isolate
对象,两个isolate
之间使用SendPort
相互发送消息,而isolate
中也存在了一个与之对应的ReceivePort
接受消息用来处理,但是我们需要注意的是,ReceivePort
和SendPort
在每个isolate
都有一对,只有同一个isolate
中的ReceivePort
才能接受到当前类的SendPort
发送的消息并且处理。
11.await for 如何使用?
参考答案:
await for
是不断获取stream
流中的数据,然后执行循环体中的操作。它一般用在直到stream
什么时候完成,并且必须等待传递完成之后才能使用,不然就会一直阻塞。 12.Stream 有哪两种订阅模式?分别是怎么调用的?
参考答案:
单订阅(single
)和多订阅(broadcast
)。
单订阅就是只能有一个订阅者,而广播是可以有多个订阅者。这就有点类似于消息服务(Message Service
)的处理模式。单订阅类似于点对点,在订阅者出现之前会持有数据,在订阅者出现之后就才转交给它。而广播类似于发布订阅模式,可以同时有多个订阅者,当有数据时就会传递给所有的订阅者,而不管当前是否已有订阅者存在。
Stream
默认处于单订阅模式,所以同一个 stream
上的 listen
和其它大多数方法只能调用一次,调用第二次就会报错。但 Stream
可以通过 transform()
方法(返回另一个 Stream
)进行连续调用。通过 Stream.asBroadcastStream()
可以将一个单订阅模式的 Stream
转换成一个多订阅模式的 Stream
,isBroadcast
属性可以判断当前 Stream
所处的模式。
13.dart中mixin机制是怎么样的?
参考答案:
mixin
是Dart 2.1 加入的特性,以前版本通常使用abstract class
代替。简单来说,mixin
是为了解决继承方面的问题而引入的机制,Dart为了支持多重继承,引入了mixin
关键字,它最大的特殊处在于:mixin
定义的类不能有构造方法,这样可以避免继承多个类而产生的父类构造方法冲突。 mixins
的对象是类,mixins
绝不是继承,也不是接口,而是一种全新的特性,可以mixins
多个类,mixins
的使用需要满足一定条件。
14.JIT 与 AOT分别是什么?
参考答案:
借助于先进的工具链和编译器,Dart 是少数同时支持 JIT(Just In Time,即时编译)和 AOT(Ahead of Time,运行前编译)的语言之一。那,到底什么是 JIT 和 AOT 呢?语言在运行之前通常都需要编译,JIT 和 AOT 则是最常见的两种编译模式。JIT 在运行时即时编译,在开发周期中使用,可以动态下发和执行代码,开发测试效率高,但运行速度和执行性能则会因为运行时即时编译受到影响。
AOT 即提前编译,可以生成被直接执行的二进制代码,运行速度快、执行性能表现好,但每次执行前都需要提前编译,开发测试效率低。
15.Dart的内存分配与垃圾回收是怎么样的?
参考答案:
Dart VM 的内存分配策略比较简单,创建对象时只需要在堆上移动指针,内存增长始终是线性的,省去了查找可用内存的过程。在 Dart 中,并发是通过 Isolate
实现的。Isolate
是类似于线程但不共享内存,独立运行的 worker
。这样的机制,就可以让 Dart 实现无锁的快速分配。
Dart 的垃圾回收,则是采用了多生代算法。新生代在回收内存时采用“半空间”机制,触发垃圾回收时,Dart 会将当前半空间中的“活跃”对象拷贝到备用空间,然后整体释放当前空间的所有内存。回收过程中,Dart 只需要操作少量的“活跃”对象,没有引用的大量“死亡”对象则被忽略,这样的回收机制很适合 Flutter 框架中大量 Widget 销毁重建的场景。
16.使用mixins的条件是什么?
参考答案:
因为mixins
使用的条件,随着Dart版本一直在变,这里讲的是Dart2.1中使用mixins
的条件:
mixins
类只能继承自object mixins
类不能有构造函数- 一个类可以
mixins
多个mixins
类 - 可以
mixins
多个类,不破坏Flutter的单继承
17.mixin 怎么指定异常类型?
参考答案:
on
关键字可用于指定异常类型。 on
只能用于被mixins
标记的类,例如mixins X on A
,意思是要mixins X
的话,得先接口实现或者继承A
。这里A
可以是类,也可以是接口,但是在mixins
的时候用法有区别.
on
一个类:
on
的是一个接口: 得首先实现这个接口,然后再用mix
18.main future mirotask 的执行顺序是怎样的?
参考答案:
普通代码都是同步执行的,结束后会开始检查microtask
中是否有任务,若有则执行,执行完继续检查microtask
,直到microtask
列队为空。最后会去执行event
队列(future
)。
19.Future和Isolate有什么区别?
参考答案:
future
是异步编程,调用本身立即返回,并在稍后的某个时候执行完成时再获得返回结果。在普通代码中可以使用await
等待一个异步调用结束。 isolate
是并发编程,Dart有并发时的共享状态,所有Dart代码都在isolate
中运行,包括最初的main()
。每个isolate
都有它自己的堆内存,意味着其中所有内存数据,包括全局数据,都仅对该isolate
可见,它们之间的通信只能通过传递消息的机制完成,消息则通过端口(port
)收发。isolate
只是一个概念,具体取决于如何实现,比如在Dart VM
中一个isolate
可能会是一个线程,在Web中可能会是一个Web Worker
。
20.Stream 与 Future是什么关系?
参考答案:
Stream
和 Future
是 Dart 异步处理的核心 API。Future
表示稍后获得的一个数据,所有异步的操作的返回值都用 Future
来表示。但是 Future
只能表示一次异步获得的数据。而 Stream
表示多次异步获得的数据。比如界面上的按钮可能会被用户点击多次,所以按钮上的点击事件(onClick
)就是一个 Stream
。简单地说,Future
将返回一个值,而Stream
将返回多次值。Dart 中统一使用 Stream
处理异步事件流。Stream
和一般的集合类似,都是一组数据,只不过一个是异步推送,一个是同步拉取。
1.介绍下Flutter的FrameWork层和Engine层,以及它们的作用
参考答案:
Flutter的FrameWork
层是用Dart编写的框架(SDK),它实现了一套基础库,包含Material
(Android风格UI)和Cupertino
(iOS风格)的UI界面,下面是通用的Widgets
(组件),之后是一些动画、绘制、渲染、手势库等。这个纯 Dart实现的 SDK被封装为了一个叫作 dart:ui
的 Dart库。我们在使用 Flutter写 App的时候,直接导入这个库即可使用组件等功能。 Flutter的Engine
层是Skia 2D
的绘图引擎库,其前身是一个向量绘图软件,Chrome和 Android均采用 Skia
作为绘图引擎。Skia提供了非常友好的 API,并且在图形转换、文字渲染、位图渲染方面都提供了友好、高效的表现。Skia是跨平台的,所以可以被嵌入到 Flutter的 iOS SDK中,而不用去研究 iOS闭源的 Core Graphics / Core Animation
。Android自带了 Skia
,所以 Flutter Android SDK要比 iOS SDK小很多。
2.介绍下Widget、State、Context 概念
参考答案:
- Widget:在Flutter中,几乎所有东西都是
Widget
。将一个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
。
3.介绍下StatelessWidget和StatefulWidget两种状态组件类
参考答案:
- StatelessWidget: 一旦创建就不关心任何变化,在下次构建之前都不会改变。它们除了依赖于自身的配置信息(在父节点构建时提供)外不再依赖于任何其他信息。比如典型的
Text
、Row
、Column
、Container
等,都是StatelessWidget
。它的生命周期相当简单:初始化、通过build()
渲染。 - StatefulWidget: 在生命周期内,该类
Widget
所持有的数据可能会发生变化,这样的数据被称为State
,这些拥有动态内部数据的Widget被称为StatefulWidget
。比如复选框、Button
等。State
会与Context
相关联,并且此关联是永久性的,State
对象将永远不会改变其Context
,即使可以在树结构周围移动,也仍将与该context
相关联。当state
与context
关联时,state
被视为已挂载。StatefulWidget
由两部分组成,在初始化时必须要在createState()
时初始化一个与之相关的State
对象。
4.StatefulWidget 的生命周期是怎么样的?
参考答案:
Flutter的Widget
分为StatelessWidget
和StatefulWidget
两种。其中,StatelessWidget
是无状态的,StatefulWidget
是有状态的,因此实际使用时,更多的是StatefulWidget
。StatefulWidget
的生命周期如下图:
initState()
:Widget
初始化当前State
,在当前方法中是不能获取到Context
的,如想获取,可以试试Future.delayed()
didChangeDependencies()
:在initState()
后调用,State
对象依赖关系发生变化的时候也会调用。deactivate()
:当State
被暂时从视图树中移除时会调用这个方法,页面切换时也会调用该方法,和Android里的onPause
差不多。dispose()
:Widget
销毁时调用。didUpdateWidget
:Widget
状态发生变化的时候调用。
5.说下Widgets、RenderObjects 和 Elements的关系
参考答案:
首先看一下这几个对象的含义及作用。
Widget
:仅用于存储渲染所需要的信息。RenderObject
:负责管理布局、绘制等操作。Element
:才是这颗巨大的控件树上的实体。
Widget
会被inflate(填充)
到Element
,并由Element
管理底层渲染树。Widget
并不会直接管理状态及渲染,而是通过State
这个对象来管理状态。Flutter创建Element
的可见树,相对于Widget
来说,是可变的,通常界面开发中,我们不用直接操作Element
,而是由框架层实现内部逻辑。就如一个UI视图树中,可能包含有多个TextWidget
(Widget
被使用多次),但是放在内部视图树的视角,这些TextWidget
都是填充到一个个独立的Element
中。Element
会持有renderObject
和widget
的实例。记住,Widget
只是一个配置,RenderObject
负责管理布局、绘制等操作。 在第一次创建 Widget
的时候,会对应创建一个 Element
, 然后将该元素插入树中。如果之后 Widget
发生了变化,则将其与旧的 Widget
进行比较,并且相应地更新 Element
。重要的是,Element
不会被重建,只是更新而已。
6.Flutter 是如何与原生Android、iOS进行通信的?
参考答案:
Flutter 通过 PlatformChannel
与原生进行交互,其中 PlatformChannel
分为三种:
BasicMessageChannel
:用于传递字符串和半结构化的信息。MethodChannel
:用于传递方法调用。Flutter主动调用Native的方法,并获取相应的返回值。EventChannel
:用于数据流(event streams
)的通信。
关于原理:www.jianshu.com/p/39575a90e…
7.简述下Flutter 的热重载
参考答案:
Flutter 的热重载是基于 JIT 编译模式的代码增量同步。由于 JIT 属于动态编译,能够将 Dart 代码编译成生成中间代码,让 Dart VM
在运行时解释执行,因此可以通过动态更新中间代码实现增量同步。
热重载的流程可以分为 5 步,包括:扫描工程改动、增量编译、推送更新、代码合并、Widget
重建。
Flutter 在接收到代码变更后,并不会让 App 重新启动执行,而只会触发 Widget
树的重新绘制,因此可以保持改动前的状态,大大缩短了从代码修改到看到修改产生的变化之间所需要的时间。
另一方面,由于涉及到状态的保存与恢复,涉及状态兼容与状态初始化的场景,热重载是无法支持的,如改动前后 Widget
状态无法兼容、全局变量与静态属性的更改、main
方法里的更改、initState
方法里的更改、枚举和泛型的更改等。
可以发现,热重载提高了调试 UI 的效率,非常适合写界面样式这样需要反复查看修改效果的场景。但由于其状态保存的机制所限,热重载本身也有一些无法支持的边界。
8.说下Flutter 和其他跨平台方案的本质区别
参考答案:
React Native 之类的框架,只是通过 JavaScript 虚拟机扩展调用系统组件,由 Android 和 iOS 系统进行组件的渲染;
Flutter 则是自己完成了组件渲染的闭环。那么,Flutter 是怎么完成组件渲染的呢?这需要从图像显示的基本原理说起。在计算机系统中,图像的显示需要 CPU、GPU 和显示器一起配合完成:CPU 负责图像数据计算,GPU 负责图像数据渲染,而显示器则负责最终图像显示。CPU 把计算好的、需要显示的内容交给 GPU,由 GPU 完成渲染后放入帧缓冲区,随后视频控制器根据垂直同步信号(VSync)以每秒 60 次的速度,从帧缓冲区读取帧数据交由显示器完成图像显示。操作系统在呈现图像时遵循了这种机制,而 Flutter 作为跨平台开发框架也采用了这种底层方案。下面有一张更为详尽的示意图来解释 Flutter 的绘制原理。 Flutter 绘制原理可以看到,Flutter 关注如何尽可能快地在两个硬件时钟的
VSync
信号之间计算并合成视图数据,然后通过 Skia
交给 GPU 渲染:UI 线程使用 Dart 来构建视图结构数据,这些数据会在 GPU 线程进行图层合成,随后交给 Skia
引擎加工成 GPU 数据,而这些数据会通过 OpenGL
最终提供给 GPU 渲染。
9.Widget 唯一标识Key有哪几种?
参考答案:
在flutter中,每个widget
都是被唯一标识的。这个唯一标识在build
或renderin
g阶段由框架定义。该标识对应于可选的Key
参数,如果省略,Flutter将会自动生成一个。
在flutter中,主要有4种类型的Key
:GlobalKey
(确保生成的Key在整个应用中唯一,是很昂贵的,允许element
在树周围移动或变更父节点而不会丢失状态)、LocalKey
、UniqueKey
、ObjectKey
。
10.什么是Navigator? MaterialApp做了什么?
参考答案:
Navigator
是在Flutter中负责管理维护页面堆栈的导航器。
MaterialApp
在需要的时候,会自动为我们创建Navigator
。
Navigator.of(context)
,会使用context
来向上遍历Element
树,找到MaterialApp
提供的_NavigatorState
再调用其push/pop
方法完成导航操作。
11.Flutter动画类型有哪些?
参考答案:
-
补间动画:给定初值与终值,系统自动补齐中间帧的动画
-
物理动画:遵循物理学定律的动画,实现了弹簧、阻尼、重力三种物理效果
在应用使用过程中常见动画模式:
- 动画列表或者网格:例如元素的添加或者删除操作;
- 转场动画
Shared element transition
:例如从当前页面打开另一页面的过渡动画; - 交错动画
Staggered animations
:比如部分或者完全交错的动画。
12.如何统一管理错误页面?
参考答案:
在main
方法修改ErrorWidget.builder
来自定义一个属于自己的Widget
;
如:
/// 自定义报错页面
ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails) {
debugPrint(flutterErrorDetails.toString());
return new Center(child: new Text("App错误,快去反馈给作者!"));
};
13.Flutter 中存在哪四大线程?
参考答案:
Flutter 中存在四大线程,分别为 UI Runner
、GPU Runner
、IO Runner
, Platform Runner
(原生主线程) ,同时在 Flutter 中可以通过 isolate
或者 compute
执行真正的跨线程异步操作。
14.PlatformView的作用有哪些?
参考答案:
Flutter 中通过 PlatformView
可以嵌套原生 View
到 Flutter UI
中;
15.PlatformView使用了哪些东西来实现?
参考答案:
Presentation
、VirtualDisplay
、 Surface
等;
16.PlatformView大致原理是怎么样的?
参考答案:
使用了类似副屏显示的技术,VirtualDisplay
类代表一个虚拟显示器,调用 DisplayManager
的 createVirtualDisplay()
方法,将虚拟显示器的内容渲染在一个 Surface
控件上,然后将 Surface
的 id
通知给 Dart,让 engine
绘制时,在内存中找到对应的 Surface
画面内存数据,然后绘制出来。 实时控件截图渲染显示技术。
17.Flutter 的 Debug 和 release 分别是在什么模式下运行的?
参考答案:
Flutter 的 Debug
下是 JIT
模式,release
下是AOT
模式。
18.Platform Channel有哪几种通信方式?分别是用于什么操作?
参考答案:
BasicMessageChannel
:用于传递字符串和半结构化的信息。MethodChannel
:用于传递方法调用(method invocation
)。EventChannel
: 用于数据流(event streams
)的通信。
19.RenderObject布局相关方法调用顺序是怎么样的?
参考答案:
layout
-> performResize
-> performLayout
-> markNeedsPaint
, 但是用户一般不会直接调用 layout
,而是通过 markNeedsLayout
,具体流程如下: 20.RenderObject如何使得页面重绘?流程是怎么样的?
参考答案:
RenderObject
在 attch/layout
之后会通过 markNeedsPaint();
使得页面重绘,流程大概如下: 通过
isRepaintBoundary
往上确定了更新区域,通过 requestVisualUpdate
方法触发更新往下绘制。
21.Flutter存在哪几棵树?他们有什么关系?
参考答案:
Flutter 中存在 Widget
、 Element
、RenderObject
、Layer
四棵树,其中 Widget
与 Element
是一对多的关系
22.简述下Flutter的线程管理模型
参考答案:
默认情况下,Flutter Engine
层会创建一个Isolate
,并且Dart代码默认就运行在这个主Isolate
上。必要时可以使用spawnUri
和spawn
两种方式来创建新的Isolate
,在Flutter中,新创建的Isolate
由Flutter进行统一的管理。 事实上,Flutter Engine
自己不创建和管理线程,Flutter Engine
线程的创建和管理是Embeder
负责的,Embeder
指的是将引擎移植到平台的中间层代码,Flutter Engine
层的架构示意图如下图所示。
在Flutter的架构中,Embeder
提供四个Task Runner
,分别是Platform Task Runner
、UI Task Runner Thread
、GPU Task Runner
和IO Task Runner
,每个Task Runner
负责不同的任务,Flutter Engine
不在乎Task Runner
运行在哪个线程,但是它需要线程在整个生命周期里面保持稳定。
1.状态管理是什么?
参考答案:
程序=算法+数据结构 数据是程序的中心。数据结构和算法两个概念间的逻辑关系贯穿了整个程序世界,首先二者表现为不可分割的关系。其实Flutter不就是一个程序吗,那我们面临的最底层的问题还是算法和数据结构,所以我们推导出
Flutter=算法+数据结构 那状态管理是什么?我也用公式来表达一下,如下:
Flutter状态管理=算法+数据结构+UI绑定
2.为什么需要状态管理?
参考答案:
用于解决状态更新问题,不需要WidgetState
被全局化,保证组件隐私,使得代码可扩展,易维护,可以动态替换UI而不影响算法逻辑,安全可靠,保持数据的稳定伸缩,性能佳,局部优化;
3.说下状态管理基本分类
参考答案:
分为局部管理和全局管理;
- 局部管理:短暂的状态,这种状态根本不需要做全局处理;
- 全局管理:即应用状态,非短暂状态,您要在应用程序的许多部分之间共享,以及希望在用户会话之间保持的状态,就是我们所说的应用程序状态(有时也称为共享状态)
4.状态管理的底层逻辑一般是怎么样的?
参考答案:
State
:如StatefulWidget
、StreamBuilder
状态管理方式;InheritedWidget
专门负责Widget
树中数据共享的功能型Widget
:如Provider
、scoped_model
就是基于它开发;Notification
:与InheritedWidget
正好相反,InheritedWidget
是从上往下传递数据,Notification
是从下往上,但两者都在自己的Widget
树中传递,无法跨越树传递;Stream
数据流 :如Bloc
、flutter_redux
、fish_redux
等也都基于它来做实现;
5.状态管理的使用原则是怎么样的?
参考答案:
局部管理优于全局、保持数据安全性、考虑页面重新build
带来的影响;
6.使用成熟状态管理库的弊端有哪些?
参考答案:
增加代码复杂性、框架bug修复需要时间等待、不理解框架原理导致使用方式不对,反而带来更多问题、选型错误导致不符合应用要求、与团队风格冲突不适用;
进阶1.flutter run实际走了哪三个命令?分别用于什么操作?
参考答案:
flutter build apk
:通过gradle
来构建APKadb install
:安装APKadb am start
:启动应用
2.setState做了哪些工作?是如何更新UI的?
参考答案:
setState
其实是调用了 markNeedsBuild
,该方法内部标记此Element
为 Dirty
,然后在下一帧 WidgetsBinding.drawFrame
才会被绘制, setState
并不是立即生效的。
3.Flutter应用启动runApp(MyApp)过程是怎么样的?
参考答案:
Flutter 中 runApp
启动入口其实是一个 WidgetsFlutterBinding
,它主要是通过 BindingBase
的子类 GestureBinding
、ServicesBinding
、 SchedulerBinding
、PaintingBinding
、SemanticsBinding
、 RendererBinding
、WidgetsBinding
等,通过 mixins
的组合而成的。
4.Dart虚拟机如何管理的?怎么调用?如何跟Flutter引擎交互?
参考答案:
Dart虚拟机拥有自己的Isolate
,完全由虚拟机自己管理的,Flutter引擎也无法直接访问。Dart的UI相关操作,是由Root Isolate
通过Dart的C++调用,或者是发送消息通知的方式,将UI渲染相关的任务提交到UIRunner
执行,这样就可以跟Flutter引擎相关模块进行交互。
5.Isolate组成部分有哪些?分别有什么作用?
参考答案:
isolate
堆是运该isolate
中代码分配的所有对象的GC
管理的内存存储;vm isolate
是一个伪isolate
,里面包含不可变对象,比如null
,true
,false
;isolate
堆能引用vm isolate
堆中的对象,但vm isolate
不能引用isolate
堆;isolate
彼此之间不能相互引用 每个isolate
都有一个执行dart代码的Mutator thread
,一个处理虚拟机内部任务(比如GC, JIT等)的helper thread
;
6.线程和isolate的关系是什么?
参考答案:
1、同一个线程在同一时间只能进入一个isolate
,当需要进入另一个isolate
则必须先退出当前的isolate
;
2、一次只能有一个Mutator
线程关联对应的isolate
,Mutator
线程是执行Dart代码并使用虚拟机的公共的C语言API的线程;
7.介绍下JIT运行模式中kernel service
参考答案:
是一个辅助类isolate
,其核心工作就是CFE
,将dart转为Kernel
二进制,然后VM
可直接使用Kernel
二进制运行在主isolate
里面运行。 8.setState在哪种场景下可能会失效?
参考答案:
1、刷新方法内声明的变量;
2、刷新被final
修饰的变量;
9.isolate是怎么进行通信的?实例化过程是怎么样的?
参考答案:
isolate
线程之间的通信主要通过port
来进行,这个port
消息传递过程是异步的。
实例化一个isolate
的过程包括:
- 1.实例化
isolate
结构体。 - 2.在堆中分配线程内存。
- 3.配置
port
等过程。
10.虚拟机如何运行Dart代码?
参考答案:
1.源码或者Kernel
二进制(JIT
)
2.snapshot :
- AOT snapshot
- AppJIT snapshot
11.JIT运行模式中debug运行原理是怎么样的?
参考答案:
将dart代码转换为kernel
二进制和执行kernel
二进制,这两个过程也可以分离开来,在两个不同的机器执行,比如host
机器执行编译,移动设备执行kernel
文件。