├── .DS_Store
├── .gitbook
└── assets
│ └── xian-yu-flutter-shi-zhan.pdf
├── .idea
├── codeStyles
│ └── Project.xml
├── flutter_interview.iml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── README.md
├── SUMMARY.md
├── flutter-mei-ri-yi-mian-mian-shi-ti-er.md
├── flutter-mei-ri-yi-mian-mian-shi-ti-san.md
├── flutter-mei-ri-yi-mian-mian-shi-ti-si.md
├── flutter-mei-ri-yi-mian-mian-shi-ti-yi.md
├── flutter_知识点.md
├── img
├── .DS_Store
├── frameworkAndEngine.jpg
├── huizhi.jpg
├── left_group.png
└── reload.png
└── ji-chu
└── untitled.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ahyangnb/flutter_interview/5e498c960005b67ba4cee6b398393b6c1bfc5ef8/.DS_Store
--------------------------------------------------------------------------------
/.gitbook/assets/xian-yu-flutter-shi-zhan.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ahyangnb/flutter_interview/5e498c960005b67ba4cee6b398393b6c1bfc5ef8/.gitbook/assets/xian-yu-flutter-shi-zhan.pdf
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | xmlns:android
11 |
12 | ^$
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | xmlns:.*
22 |
23 | ^$
24 |
25 |
26 | BY_NAME
27 |
28 |
29 |
30 |
31 |
32 |
33 | .*:id
34 |
35 | http://schemas.android.com/apk/res/android
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | .*:name
45 |
46 | http://schemas.android.com/apk/res/android
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | name
56 |
57 | ^$
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | style
67 |
68 | ^$
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | .*
78 |
79 | ^$
80 |
81 |
82 | BY_NAME
83 |
84 |
85 |
86 |
87 |
88 |
89 | .*
90 |
91 | http://schemas.android.com/apk/res/android
92 |
93 |
94 | ANDROID_ATTRIBUTE_ORDER
95 |
96 |
97 |
98 |
99 |
100 |
101 | .*
102 |
103 | .*
104 |
105 |
106 | BY_NAME
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/.idea/flutter_interview.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | 1586834294512
109 |
110 |
111 | 1586834294512
112 |
113 |
114 | 1586834341531
115 |
116 |
117 |
118 | 1586834341531
119 |
120 |
121 | 1586834468998
122 |
123 |
124 |
125 | 1586834468999
126 |
127 |
128 | 1593839294149
129 |
130 |
131 |
132 | 1593839294149
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
187 |
188 |
189 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 | 1.8
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [ahyangnb](https://github.com/ahyangnb)
2 |
3 | ## flutter\_interview
4 |
5 | Flutter面试题和答案收集,各种知识点的深入研究,学完之后征服你的面试官。
6 |
7 | ## 算是flutter最完整题库了
8 | [https://juejin.im/post/5ef58a296fb9a07ea76fd8c7](https://juejin.im/post/5ef58a296fb9a07ea76fd8c7)
9 |
10 | ## 目录
11 |
12 | * [**Flutter每日一面(面试题一)**](https://github.com/ahyangnb/flutter_interview/issues/1)
13 |
14 | > 屏幕适配,isolate通信和原理,热重载原理和过程,Flutter性能,跨平台区别,组件渲染。
15 |
16 | * \*\*\*\*[**Flutter每日一面(面试题二)**](https://github.com/ahyangnb/flutter_interview/issues/2)\*\*\*\*
17 |
18 | > Flutter绘制流程,Widget 和 element 和 RenderObject 之间的关系,特殊方法的执行顺序,Future和Isolate区别,Stream订阅模式,await for的使用,Widget、State、Context 的核心概念,key和Navigator。
19 |
20 | * \*\*\*\*[**Flutter每日一面(面试题三)**](https://github.com/ahyangnb/flutter_interview/issues/3)\*\*\*\*
21 |
22 | > Dart 语言的特性,Dart 语言重要概念,mixin extends implement 之间关系,mixins的条件,mixin 指定异常类型。
23 |
24 | * \*\*\*\*[**Flutter每日一面(面试题四)**](https://github.com/ahyangnb/flutter_interview/issues/4)\*\*\*\*
25 |
26 | > Flutter优缺点以及理念架构,Flutter的FrameWork层和Engine层。
27 | * \*\*\*\*[**Flutter每日一面(面试题五)**](https://github.com/ahyangnb/flutter_interview/issues/5)\*\*\*\*
28 |
29 | > Flutter加载部分。
30 |
31 | ## 提示
32 | 更多的正在更新!
33 |
34 | ## Flutter微信群
35 |
36 |
37 |
38 | [上图无法显示点我](http://www.flutterj.com/left_group.png)
39 |
40 | Flutter教程网:www.flutterj.com
41 |
42 | Flutter交流QQ群:[874592746](https://jq.qq.com/?_wv=1027&k=5coTYqE)
43 |
44 | ## 公众号
45 |
46 |
47 |
48 | 关注公众号“`Flutter前线`”,各种Flutter项目实战经验技巧,干活知识,Flutter面试题答案,等你来领取。
49 |
50 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Table of contents
2 |
3 | * [主页](README.md)
4 | * [Flutter每日一面(面试题一)](flutter-mei-ri-yi-mian-mian-shi-ti-yi.md)
5 | * [Flutter每日一面(面试题二)](flutter-mei-ri-yi-mian-mian-shi-ti-er.md)
6 | * [Flutter每日一面(面试题三)](flutter-mei-ri-yi-mian-mian-shi-ti-san.md)
7 | * [Flutter每日一面(面试题四)](flutter-mei-ri-yi-mian-mian-shi-ti-si.md)
8 |
9 | ## 基础
10 |
11 | * [Untitled](ji-chu/untitled.md)
12 | * [flutter教程网](http://www.flutterj.com/)
13 |
14 |
--------------------------------------------------------------------------------
/flutter-mei-ri-yi-mian-mian-shi-ti-er.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | Flutter绘制流程,Widget 和 element 和 RenderObject
4 | 之间的关系,特殊方法的执行顺序,Future和Isolate区别,Stream订阅模式,await for的使用,Widget、State、Context
5 | 的核心概念,key和Navigator。
6 | ---
7 |
8 | # Flutter每日一面(面试题二)
9 |
10 |
11 |
12 | * **1.Flutter绘制流程是怎么样的?**
13 |
14 | **答案:**
15 |
16 | > Flutter只关心向 GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在 GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为 GPU数据,这些数据通过 OpenGL或者 Vulkan提供给 GPU。
17 |
18 | 所以 Flutter并不关心显示器、视频控制器以及 GPU具体工作,它只关心 GPU发出的 VSync信号,尽可能快地在两个 VSync信号之间计算并合成视图数据,并且把数据提供给 GPU。
19 |
20 | 
21 |
22 | * **2.说下Widget 和 element 和 RenderObject 之间的关系?**
23 |
24 | **答案:**
25 |
26 | * Widget是用户界面的一部分,并且是不可变的。
27 | * Element是在树中特定位置Widget的实例。
28 | * RenderObject是渲染树中的一个对象,它的层次结构是渲染库的核心。
29 |
30 | Widget会被inflate(填充)到Element,并由Element管理底层渲染树。Widget并不会直接管理状态及渲染,而是通过State这个对象来管理状态。Flutter创建Element的可见树,相对于Widget来说,是可变的,通常界面开发中,我们不用直接操作Element,而是由框架层实现内部逻辑。就如一个UI视图树中,可能包含有多个TextWidget\(Widget被使用多次\),但是放在内部视图树的视角,这些TextWidget都是填充到一个个独立的Element中。Element会持有renderObject和widget的实例。记住,Widget 只是一个配置,RenderObject 负责管理布局、绘制等操作。
31 |
32 | 在第一次创建 Widget 的时候,会对应创建一个 Element, 然后将该元素插入树中。如果之后 Widget 发生了变化,则将其与旧的 Widget 进行比较,并且相应地更新 Element。重要的是,Element 不会被重建,只是更新而已。
33 |
34 | * **3.Flutter main future mirotask 的执行顺序是怎么样的?**
35 |
36 | **答案:**
37 |
38 | > 普通代码都是同步执行的,结束后会开始检查microtask中是否有任务,若有则执行,执行完继续检查microtask,直到microtask列队为空。最后会去执行event队列(future)。
39 |
40 | * **4.Future和Isolate有什么区别?**
41 |
42 | **答案:**
43 |
44 | > future是异步编程,调用本身立即返回,并在稍后的某个时候执行完成时再获得返回结果。在普通代码中可以使用await 等待一个异步调用结束。
45 |
46 | > isolate是并发编程,Dartm有并发时的共享状态,所有Dart代码都在isolate中运行,包括最初的main\(\)。每个isolate都有它自己的堆内存,意味着其中所有内存数据,包括全局数据,都仅对该isolate可见,它们之间的通信只能通过传递消息的机制完成,消息则通过端口\(port\)收发。isolate只是一个概念,具体取决于如何实现,比如在Dart VM中一个isolate可能会是一个线程,在Web中可能会是一个Web Worker。
47 |
48 | * **5.Stream 与 Future是什么关系?**
49 |
50 | **答案:**
51 |
52 | > Stream 和 Future 是 Dart 异步处理的核心 API。Future 表示稍后获得的一个数据,所有异步的操作的返回值都用 Future 来表示。但是 Future 只能表示一次异步获得的数据。而 Stream 表示多次异步获得的数据。比如界面上的按钮可能会被用户点击多次,所以按钮上的点击事件(onClick)就是一个 Stream 。简单地说,Future将返回一个值,而Stream将返回多次值。Dart 中统一使用 Stream 处理异步事件流。Stream 和一般的集合类似,都是一组数据,只不过一个是异步推送,一个是同步拉取。
53 |
54 | * **6.Stream 有哪两种订阅模式?分别是怎么调用的?**
55 |
56 | **答案:**
57 |
58 | Stream有两种订阅模式:单订阅\(single\) 和 多订阅(broadcast)。单订阅就是只能有一个订阅者,而广播是可以有多个订阅者。这就有点类似于消息服务(Message Service)的处理模式。单订阅类似于点对点,在订阅者出现之前会持有数据,在订阅者出现之后就才转交给它。而广播类似于发布订阅模式,可以同时有多个订阅者,当有数据时就会传递给所有的订阅者,而不管当前是否已有订阅者存在。
59 |
60 | Stream 默认处于单订阅模式,所以同一个 stream 上的 listen 和其它大多数方法只能调用一次,调用第二次就会报错。但 Stream 可以通过 transform\(\) 方法(返回另一个 Stream)进行连续调用。通过 Stream.asBroadcastStream\(\) 可以将一个单订阅模式的 Stream 转换成一个多订阅模式的 Stream,isBroadcast 属性可以判断当前 Stream 所处的模式。
61 |
62 | * **7.await for 如何使用?**
63 |
64 | **答案:**
65 |
66 | > await for是不断获取stream流中的数据,然后执行循环体中的操作。它一般用在直到stream什么时候完成,并且必须等待传递完成之后才能使用,不然就会一直阻塞。
67 |
68 | ```dart
69 | Stream stream = new Stream.fromIterable(['不开心', '面试', '没', '过']);
70 | main() async{
71 | print('上午被开水烫了脚');
72 | await for(String s in stream){
73 | print(s);
74 | }
75 | print('晚上还没吃饭');
76 | }
77 | ```
78 |
79 | * **8.Flutter中的Widget、State、Context 的核心概念?是为了解决什么问题?**
80 |
81 | **答案:**
82 |
83 | * Widget: 在Flutter中,几乎所有东西都是Widget。将一个Widget想象为一个可视化的组件(或与应用可视化方面交互的组件),当你需要构建与布局直接或间接相关的任何内容时,你正在使用Widget。
84 | * Widget树: Widget以树结构进行组织。包含其他Widget的widget被称为父Widget\(或widget容器\)。包含在父widget中的widget被称为子Widget。
85 | * Context: 仅仅是已创建的所有Widget树结构中的某个Widget的位置引用。简而言之,将context作为widget树的一部分,其中context所对应的widget被添加到此树中。一个context只从属于一个widget,它和widget一样是链接在一起的,并且会形成一个context树。
86 | * State: 定义了StatefulWidget实例的行为,它包含了用于”交互/干预“Widget信息的行为和布局。应用于State的任何更改都会强制重建Widget。
87 |
88 | > 这些状态的引入,主要是为了解决多个部件之间的交互和部件自身状态的维护。
89 |
90 | * **9.Widget分别有哪两种状态类?**
91 |
92 | **答案:**
93 |
94 | > StatelessWidget: 一旦创建就不关心任何变化,在下次构建之前都不会改变。它们除了依赖于自身的配置信息(在父节点构建时提供)外不再依赖于任何其他信息。比如典型的Text、Row、Column、Container等,都是StatelessWidget。它的生命周期相当简单:初始化、通过build\(\)渲染。
95 |
96 | > StatefulWidget: 在生命周期内,该类Widget所持有的数据可能会发生变化,这样的数据被称为State,这些拥有动态内部数据的Widget被称为StatefulWidget。比如复选框、Button等。State会与Context相关联,并且此关联是永久性的,State对象将永远不会改变其Context,即使可以在树结构周围移动,也仍将与该context相关联。当state与context关联时,state被视为已挂载。StatefulWidget由两部分组成,在初始化时必须要在createState\(\)时初始化一个与之相关的State对象。
97 |
98 | * **10.Widget 唯一标识Key有那几种?**
99 |
100 | **答案:**
101 |
102 | > 在flutter中,每个widget都是被唯一标识的。这个唯一标识在build或rendering阶段由框架定义。该标识对应于可选的Key参数,如果省略,Flutter将会自动生成一个。
103 |
104 | > 在flutter中,主要有4种类型的Key:GlobalKey(确保生成的Key在整个应用中唯一,是很昂贵的,允许element在树周围移动或变更父节点而不会丢失状态)、LocalKey、UniqueKey、ObjectKey。
105 |
106 | * **11.Navigator是什么,为什么Navigator可以实现无需上下文路由导航?**
107 |
108 | **答案:**
109 |
110 | > Navigator是在Flutter中负责管理维护页面堆栈的导航器。MaterialApp在需要的时候,会自动为我们创建Navigator。Navigator.of\(context\),会使用context来向上遍历Element树,找到MaterialApp提供的NavigatorState再调用其push/pop方法完成导航操作。
111 |
112 | > 所以如果在MaterialApp的navigatorKey属性内设置好一个Key就可以直接使用这个Key来进行路由导航,无需上下文。
113 |
114 | #### [下一篇:Flutter每日一面(面试题三)](https://github.com/ahyangnb/flutter_interview/issues/3)
115 |
116 | #### [Flutter每日一面目录大全](https://github.com/ahyangnb/flutter_interview)
117 |
118 |
--------------------------------------------------------------------------------
/flutter-mei-ri-yi-mian-mian-shi-ti-san.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Dart 语言的特性,Dart 语言重要概念,mixin extends implement 之间关系,mixins的条件,mixin 指定异常类型。
3 | ---
4 |
5 | # Flutter每日一面(面试题三)
6 |
7 |
8 |
9 | * **1.Dart 语言的特性是怎么样的?**
10 |
11 | **答案:**
12 |
13 | * Productive(生产力高,Dart的语法清晰明了,工具简单但功能强大)
14 | * Fast(执行速度快,Dart提供提前优化编译,以在移动设备和Web上获得可预测的高性能和快速启动。)
15 | * Portable(易于移植,Dart可编译成ARM和X86代码,这样Dart移动应用程序可以在iOS、Android和其他地方运行)
16 | * Approachable(容易上手,充分吸收了高级语言特性,如果你已经知道C++,C语言,或者Java,你可以在短短几天内用Dart来开发)
17 | * Reactive(响应式编程)
18 | * **2.Dart 语言有哪些重要的概念?**
19 |
20 | **答案:**
21 |
22 | * 在Dart中,一切都是对象,所有的对象都是继承自Object
23 | * Dart是强类型语言,但可以用var或 dynamic来声明一个变量,Dart会自动推断其数据类型,dynamic类似c\#
24 | * 没有赋初值的变量都会有默认值null
25 | * Dart支持顶层方法,如main方法,可以在方法内部创建方法
26 | * Dart支持顶层变量,也支持类变量或对象变量
27 | * Dart没有public protected private等关键字,如果某个变量以下划线(\_)开头,代表这个变量在库中是私有的
28 | * **3.说下mixin extends implement 之间的关系?**
29 |
30 | **答案:**
31 |
32 | > 继承(关键字 extends)、混入 mixins (关键字 with)、接口实现(关键字 implements)。这三者可以同时存在,前后顺序是`extends -> mixins -> implements`。
33 |
34 | > Flutter中的继承是单继承,子类重写超类的方法要用`@Override`,子类调用超类的方法要用super。
35 | >
36 | > 在Flutter中,Mixins是一种在多个类层次结构中复用类代码的方法。mixins的对象是类,mixins绝不是继承,也不是接口,而是一种全新的特性,可以mixins多个类,mixins的使用需要满足一定条件。
37 |
38 | * **4.使用mixins的条件是什么?**
39 |
40 | **答案:**
41 |
42 | 随着Dart版本一直在变,这里讲的是Dart2.1中使用mixins的条件:
43 |
44 | * mixins类只能继承自object
45 | * mixins类不能有构造函数
46 | * 一个类可以mixins多个mixins类
47 | * 可以mixins多个类,不破坏Flutter的单继承
48 | * **5.mixin 怎么指定异常类型?**
49 |
50 | **答案:**
51 |
52 | on关键字可用于指定异常类型。 on只能用于被mixins标记的类,例如mixins X on A,意思是要mixins X的话,得先接口实现或者继承A。这里A可以是类,也可以是接口,但是在mixins的时候用法有区别.
53 |
54 | on 一个类:
55 |
56 | ```dart
57 | class A {
58 | void a(){
59 | print("a");
60 | }
61 | }
62 |
63 |
64 | mixin X on A{
65 | void x(){
66 | print("x");
67 | }
68 | }
69 |
70 |
71 | class mixinsX extends A with X{
72 | }
73 | ```
74 |
75 | on 的是一个接口: 得首先实现这个接口,然后再用mix
76 |
77 | ```dart
78 | class A {
79 | void a(){
80 | print("a");
81 | }
82 | }
83 |
84 | mixin X on A{
85 | void x(){
86 | print("x");
87 | }
88 | }
89 |
90 | class implA implements A{
91 | @override
92 | void a() {}
93 | }
94 |
95 | class mixinsX2 extends implA with X{
96 | }
97 | ```
98 |
99 | #### [下一篇:Flutter每日一面(面试题四)](https://github.com/ahyangnb/flutter_interview/issues/4)
100 |
101 | #### [Flutter每日一面目录大全](https://github.com/ahyangnb/flutter_interview)
102 |
103 |
--------------------------------------------------------------------------------
/flutter-mei-ri-yi-mian-mian-shi-ti-si.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Flutter优缺点以及理念架构,Flutter的FrameWork层和Engine层。
3 | ---
4 |
5 | # Flutter每日一面(面试题四)
6 |
7 |
8 |
9 | * **1.简单的说说Flutter优缺点以及理念架构:**
10 |
11 | **答案:**
12 |
13 | **优点**
14 |
15 | * 热重载(Hot Reload),利用Android Studio直接一个ctrl+s就可以保存并重载,模拟器立马就可以看见效果,相比原生冗长的编译过程强很多;
16 | * 一切皆为Widget的理念,对于Flutter来说,手机应用里的所有东西都是Widget,通过可组合的空间集合、丰富的动画库以及分层课扩展的架构实现了富有感染力的灵活界面设计;
17 | * 借助可移植的GPU加速的渲染引擎以及高性能本地代码运行时以达到跨平台设备的高质量用户体验。 简单来说就是:最终结果就是利用Flutter构建的应用在运行效率上会和原生应用差不多。
18 |
19 | #### 缺点
20 |
21 | * 不支持热更新;
22 | * 三方库很少,需要自己造轮子(不过现在越来越多了,社区也越来越强了);
23 | * dart语言编写,掌握该语言的开发者很少(不过有其他语言基础的掌握起来也特别容易)。
24 |
25 | #### 理念架构
26 |
27 | Flutter 主要分为 Framework 和 Engine,我们基于Framework 开发App,运行在 Engine 上。Engine 是 Flutter 的独立虚拟机,由它适配和提供跨平台支持,目前猜测 Flutter 应用程序在 Android 上,是直接运行 Engine 上 所以在是不需要Dalvik虚拟机。(这是比kotlin更彻底,抛弃JVM的纠缠? ) 得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用自己 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是通过 AOT 编译为平台的原生代码,所以 Flutter 可以 直接与平台通信,不需要JS引擎的桥接。同时 Flutter 唯一要求系统提供的是 canvas,以实现UI的绘制。
28 |
29 | * **2.简单的解释下Flutter的FrameWork层和Engine层:**
30 |
31 | **答案:**
32 |
33 | **FrameWork层**
34 |
35 | Flutter的顶层是用drat编写的框架(SDK),它实现了一套基础库,包含Material(Android风格UI)和Cupertino(iOS风格)的UI界面,下面是通用的Widgets(组件),之后是一些动画、绘制、渲染、手势库等。这个纯 Dart实现的 SDK被封装为了一个叫作 dart:ui的 Dart库。我们在使用 Flutter写 App的时候,直接导入这个库即可使用组件等功能。
36 |
37 | #### Engine层
38 |
39 | * Skia是Google的一个 2D的绘图引擎库,其前身是一个向量绘图软件,Chrome和 Android均采用 Skia作为绘图引擎。Skia提供了非常友好的 API,并且在图形转换、文字渲染、位图渲染方面都提供了友好、高效的表现。Skia是跨平台的,所以可以被嵌入到 Flutter的 iOS SDK中,而不用去研究 iOS闭源的 Core Graphics / Core Animation。Android自带了 Skia,所以 Flutter Android SDK要比 iOS SDK小很多。
40 | * 第二是Dart 运行时环境
41 | * 第三文本渲染布局引擎。
42 |
43 | 
44 |
45 | #### [Flutter每日一面目录大全](https://github.com/ahyangnb/flutter_interview)
46 |
47 |
--------------------------------------------------------------------------------
/flutter-mei-ri-yi-mian-mian-shi-ti-yi.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: 屏幕适配,isolate通信和原理,热重载原理和过程,Flutter性能,跨平台区别,组件渲染。
3 | ---
4 |
5 | # Flutter每日一面(面试题一)
6 |
7 |
8 |
9 | ## **1.Flutter屏幕算法面试题基础\(一\):**
10 |
11 | 假如蓝湖设计图给你一张轮播图,宽度是 x 高度是 y(x px \* y px),左右间隔是t,如何使用屏幕算法适配全机型屏幕宽和高?
12 |
13 | 其实这种形式是可以直接用`AspectRatio`写宽高比,但是面试官要求手动算出来,可能这里答案不止一个,如果大家有更好的可以在下方评论出来。
14 |
15 | **答案:**
16 |
17 | > 宽度:整宽 - t _2(左右的)。 高度:\(整宽 - t_ 2 \) \* y / x。
18 |
19 | ## **2.Flutter屏幕算法面试题基础\(二\):**
20 |
21 | 假如蓝湖设计图给你一个未知数据数量有规则的列表视图,要求一行显示5个,每个间隔为10(含上下),最外边距`margin`左右都为20,高度为50,多出的数据继续往下排并向左对齐,适配任何机型,你会使用什么组件?怎么做适配?
22 |
23 | **答案:**
24 |
25 | > 使用组件:Wrap spacing和runSpacing都设置为10间隔, 然后Item的高度设置为50,宽度算法为: \( 整宽 - (外边的margin + 内边的space) \) / 5
26 |
27 | ## **3 isolate是怎么进行通信和实例化的?**
28 |
29 | * **答案:**
30 |
31 | > isolate线程之间的通信主要通过port来进行,这个port消息传递过程是异步的。通过dart源码可以看出,实例化一个isolate的过程包括: 1.实例化isolate结构体。 2.在堆中分配线程内存。 3.配置port等过程。
32 |
33 | 代码示例: 下面是一个isolate的例子,例子中新建了一个isolate,并且绑定了一个方法网络请求和数据解析处理,并通过port将处理好的数据返回给调用方。
34 |
35 | ```dart
36 | loadData() async {
37 | // 通过spawn新建一个isolate,并绑定静态方法
38 | ReceivePort receivePort = ReceivePort();
39 | await Isolate.spawn(dataLoader, receivePort.sendPort);
40 |
41 | // 获取新的isolate监听port
42 | SendPort sendPort = await receivePort.first;
43 | //调用sendReceive自定义方法
44 | List dataList = await sendReceive(sendPort,
45 | 'http://www.flutterj.com');
46 | print('dataList $dataList');
47 | }
48 |
49 | // isolate绑定方法
50 | static dataLoader(SendPort sendPort) async {
51 | // 创建监听port,并将sendPort传给外界来调用
52 | ReceivePort receivePort = ReceivePort();
53 | sendPort.send(receivePort.sendPort);
54 | // 监听外界调用
55 | await for (var msg in receivePort) {
56 | String requestURL = msg[0];
57 | SendPort callbackPort = msg[1];
58 |
59 | Client client = Client();
60 | Response response = await client.get(requestURL);
61 | List dataList = json.decode(response.body);
62 | // 回调返回值给调用者
63 | callbackPort.send(dataList);
64 | }
65 | }
66 |
67 | // 创建自己的监听port,并且向新的isolate发送消息
68 | Future sendReceive(SendPort sendPort, String url) {
69 | ReceivePort receivePort = ReceivePort();
70 | sendPort.send([url, receivePort.sendPort]);
71 | // 接收到返回值, 返回给调用者
72 | return receivePort.first;
73 | }
74 | ```
75 |
76 | ## **4.Flutter是怎么实现热重载的,原理和过程是怎么样的?**
77 |
78 | * **答案:**
79 |
80 | Flutter热重载是基于`State`的,也就是我们在代码中经常出现的`setState`方法,通过这个来修改后,会执行相应的build方法,这就是热重载的基本过程。
81 |
82 | 实现源码在下面路径中,包含文件`run_cold.dart`和`run_hot.dart`两个文件,前者负责冷启动,后者负责热重载。
83 |
84 | ```dart
85 | ~/flutter/packages/flutter_tools/lib/src/run_hot.dart
86 | ```
87 |
88 | #### 热重载实现过程:
89 |
90 | 代码在run\_hot.dart文件中,HotRunner负责具体代码执行。 当Flutter热重载时,调用restart函数,函数内部会传入一个fullRestart的bool类型变量。 热重载分为全量和非全量,fullRestart参数金牛是表示是否为全量。 以非全量热重载为例,函数的fullRestart会传入false,根据传入false参数,下面是哪部核心代码。
91 |
92 | ```dart
93 | Future restart(
94 | {bool fullRestart = false,
95 | bool pauseAfterRestart = false,
96 | String reason}) async {
97 | if (fullRestart) {
98 | // .....
99 | } else {
100 | final bool reloadOnTopOfSnapshot = _runningFromSnapshot;
101 | final String progressPrefix =
102 | reloadOnTopOfSnapshot ? 'Initializing' : 'Performing';
103 | final Status status = logger.startProgress('$progressPrefix hot reload...',
104 | progressId: 'hot.reload');
105 | OperationResult result;
106 | try {
107 | result = await _reloadSources(pause: pauseAfterRestart, reason: reason);
108 | } finally {
109 | status.cancel();
110 | }
111 | }
112 | }
113 | ```
114 |
115 | 调用Restart函数后,内部会调用\_reloadSources函数,去执行内部逻辑。
116 |
117 | 执行流程图: 
118 |
119 | 图解:
120 |
121 | 在\_reloadSources函数内部,会调用\_updateDevFs函数,函数内部会扫描修改的文件,并将修改的文件进行对比,随后将被改动代码生成一个kernel files文件。 然后通过HTTP Server将生成的kernel files文件发送给Dart VM虚拟机,虚拟机拿到kernel文件后会调用\_reloadSources函数进行资源重载,将kernel文件注入正在运行的Dart VM中,当资源重载完成后,会调用RPC接口触发Widgets的重绘。
122 |
123 | ## **5.为什么说Flutter性能好?说下和其他跨平台的本质区别!**
124 |
125 | * **答案:**
126 |
127 | > 与用于构建移动应用程序的其他大多数框架不同,Flutter是重写了一整套包括底层渲染逻辑和上层开发语言的完整解决方案。这样不仅可以保证视图渲染在Android和iOS上的高度一致性,在代码执行效率和渲染性能上也可以媲美原生App的体验。这,就是Flutter和其他跨平台方案的本质区别。
128 |
129 | ## **6.Flutter是怎么完成组件渲染的?**
130 |
131 | * **答案:**
132 |
133 | 在计算机系统中,图像的显示需要CPU、GPU和显示器一起配合完成CPU负责图像数据计算,GPU负责图像数据渲染,而显示器则负责最终图像显示。CPU把计算好的、需要显示的内容交给GPU,由GPU完成渲染后放入帧缓冲区,随后视频控制器根据垂直同步信号以每秒60次的速度,从帧缓冲区读取帧数据交由显示器完成图像显示。操作系统在呈现图像时遵循了这种机制。
134 |
135 | 而Flutter作为跨平台开发框架也采用了这种底层方案,UI线程使用Dart语言来构建视图结构数据,这些数据会在GPU线程进行图层合成,随后交给图像渲染引擎Skia加工成GPU数据,而这些数据会通过OpenGL最终提供给GPU渲染。
136 |
137 | 可以看到Flutter用了计算机最基本的图像渲染技术,摒弃其他一些通道和过程,用最直接的方式完成了图形显示,自然性能也就得到了保障。
138 |
139 | #### [下一篇:Flutter每日一面(面试题二)](https://github.com/ahyangnb/flutter_interview/issues/2)
140 |
141 | #### [Flutter每日一面目录大全](https://github.com/ahyangnb/flutter_interview)
142 |
143 |
--------------------------------------------------------------------------------
/flutter_知识点.md:
--------------------------------------------------------------------------------
1 | # Dart
2 |
3 | * 1.级联操作符
4 |
5 | Dart 中 **级联操作符** 可以返回对象从而继续执行其他方法:
6 |
7 | ```dart
8 | new Column(
9 | children: [
10 | new Container(),
11 | ]
12 | ..addAll(List.generate(3, (index) {
13 | return Container();
14 | }))
15 | ..addAll([
16 | new HorizontalLine(height: 5),
17 | ]),
18 | );
19 | ```
20 |
21 | * 2.一次性执行匿名回调函数
22 |
23 | Dart支持一次性执行匿名回调函数,如:
24 |
25 | ```dart
26 | void test() {
27 | () {
28 | print('hi');
29 | }();
30 | }
31 | ```
32 |
33 | 也可在组件中运用并接收参数,如:
34 |
35 | ```dart
36 | @override
37 | Widget build(BuildContext context) {
38 | return new Scaffold(
39 | body: new Text((String text) {
40 | return text;
41 | }('我是文字')),
42 | }
43 | ```
44 |
45 | * 3.可选方法参数
46 |
47 | `Dart` 方法可以设置 **参数默认值** 和 **指定名称** 。
48 |
49 | 比如: `getDetail(Sting userName, reposName, {branch = "master"}){}` 方法,这里 branch 不设置的话,默认是 “master” 。参数类型 可以指定或者不指定。调用效果: `getRepositoryDetailDao(“aaa", "bbbb", branch: "dev");` 。
50 |
51 | * 4.Assert(断言)
52 |
53 | `assert` 只在检查模式有效,在开发过程中,`assert(unicorn == null);` 只有条件为真才正常,否则直接抛出异常,一般用在开发过程中,某些地方不应该出现什么状态的判断。
54 |
55 | * 4.扩展
56 |
57 | 扩展可以给指定类型的数值增加获取方法,如(ScreenUtil给num加的扩展):
58 |
59 | ```dart
60 | extension SizeExtension on num {
61 | num get w => ScreenUtil().setWidth(this);
62 |
63 | num get h => ScreenUtil().setHeight(this);
64 |
65 | num get sp => ScreenUtil().setSp(this);
66 |
67 | num get ssp => ScreenUtil().setSp(this, allowFontScalingSelf: true);
68 | }
69 | ```
70 |
71 | 比如我想获取一个ScreenUtil适配的50宽度值:
72 |
73 | ```dart
74 | Container(width: 50.w)
75 | ```
76 |
77 | 等同于:
78 |
79 | ```dart
80 | Container(width: ScreenUtil().setWidth(50))
81 | ```
82 |
83 | 从而简化了代码,提升了开发效率。
84 |
85 | * 5.runZoned
86 |
87 | 可以在自己的区域中运行指定代码(根据zoneSpecification使用Zone.fork创建的区域),如果代码出现错误将抛出全局错误在onError:
88 |
89 | ```dart
90 | runZoned(() {
91 | runApp(MyApp());
92 | }, onError: (Object obj, StackTrace stack) {
93 | print(obj);
94 | print(stack);
95 | });
96 | ```
97 |
98 | 我们通用的错误信息统计平台如sentry,一般都是放在runZoned的onError内。
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | # 组件
107 |
108 | * 1.ListView自动内边距
109 |
110 | ListView会在脚手架中未写AppBar的情况下自动添加padding内边距,内边距值是状态栏高度。
111 |
112 | * 2.Draggable重绘问题
113 |
114 | Draggable的child和feedback是同一个组件是每次拖动都会重绘组件,如果不想被重绘,在组件的key给个GlobalKey即可。
115 |
116 | * 3.拿到数组模型索引
117 |
118 | List.generate可以获得数组模型的索引index,length写数组模型的长度即可。
119 |
120 | * 4.输入框内容被清空
121 |
122 | 如果出现输入框内容输入的时候突然返回到桌面,回来的时候被清空了,可以尝试使用WidgetsBindingObserver监听不可见生命周期,输入框焦点自动取消,从而输入框会保存原有内容。(这个问题在早期flutter版本出现)
123 |
124 | * 5.刷新页面的指定组件
125 |
126 | 如果只想刷新某个页面的指定组件可使用GlobalKey包裹此组件的State类,调用此组件的时候传过去,想刷新的时候就可以在外面调用这个GlobalKey的setState或其他刷新方法了。
127 |
128 | 详情:[http://book.flutterj.com/chapter2/partial_refresh.html](http://book.flutterj.com/chapter2/partial_refresh.html)
129 |
130 | * 6.拿特殊滑动组件内控制器
131 |
132 | 特殊滑动组件如NestedScrollView是有内外控制器的,普通的赋值controller只能拿到外部的滑动值,想要拿到内控制可以在NestedScrollView的body中类在上下文获取,调用上下文的ancestorWidgetOfExactType
133 |
134 | ```dart
135 |
136 | class DataBody extends StatefulWidget {
137 | @override
138 | _DataBodyState createState() => _DataBodyState();
139 | }
140 |
141 | class _DataBodyState extends State {
142 | ScrollController pageScrollController;
143 |
144 | Type typeOf() => T;
145 |
146 | @override
147 | void initState() {
148 | super.initState();
149 |
150 | PrimaryScrollController primaryScrollController =
151 | context.ancestorWidgetOfExactType(typeOf());
152 |
153 | pageScrollController = primaryScrollController.controller;
154 | }
155 | }
156 | ```
157 |
158 | 不过这个在1.12已被废弃,新版flutter使用findAncestorWidgetOfExactType代替。
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | # 功能
169 |
170 | * 1.无需上下文路由
171 |
172 | 自己定义个NavigatorState的全局key然后赋值到MaterialApp的navigatorKey就能使用NavigatorState的所有功能并无需上下文。
173 |
174 | 详情:[http://book.flutterj.com/chapter2/no_context_route.html](http://book.flutterj.com/chapter2/no_context_route.html)
175 |
176 | * 2.Future执行完成错误
177 |
178 | 如果出现Future执行完成错误可尝试使用Completer的future,如:
179 |
180 | ```dart
181 | Future _refreshData() {
182 | final Completer completer = new Completer();
183 |
184 | new Future.delayed(new Duration(seconds: 2), () {
185 | completer.complete(null);
186 | });
187 |
188 | return completer.future;
189 | }
190 |
191 | ```
192 |
193 | * 3.调用方法出现null错误
194 |
195 | dispose销毁某对象时在调用`.dispose`前加个`?`问号,可以避免前面的为空导致调用不到dispose方法报错。
196 |
197 | * 4.页面状态保存
198 |
199 | Flutter 中可以通过 `mixins AutomaticKeepAliveClientMixin` ,然后重写 `wantKeepAlive` 保持住页面,记得在被保持住的页面 `build` 中调用 `super.build` 。
200 |
201 | * 5.手势识别范围
202 |
203 | 使用GestureDetector范围只有child的设定颜色或使用区域才可被触发,behavior为HitTestBehavior.translucent时整个child会被触发,InkWell组件默认整个child会被触发。
204 |
205 | * 6.Flutter 手势事件主要是通过竞技判断的:
206 |
207 | 主要有 `hitTest` 把所有需要处理的控件对应的 `RenderObject` , 从 `child` 到 `parent` 全部组合成列表,从最里面一直添加到最外层。
208 |
209 | 然后从队列头的 child 开始 for 循环执行 `handleEvent` 方法,执行 `handleEvent` 的过程不会被拦截打断。
210 |
211 | 一般情况下 Down 事件不会决出胜利者,大部分时候是在 MOVE 或者 UP 的时候才会决出胜利者。
212 |
213 | **竞技场关闭时只有一个的就直接胜出响应,没有胜利者就拿排在队列第一个强制胜利响应。**
214 |
215 | 同时还有 `didExceedDeadline` 处理按住时的 Down 事件额外处理,同时手势处理一般在 `GestureRecognizer` 的子类进行。
216 |
217 |
218 |
219 |
220 |
221 | # 插件开发
222 |
223 | * 1.android获取context和activity
224 |
225 | 可以在插件的Plugin类实现个ActivityAware,然后在onAttachedToActivity和onReattachedToActivityForConfigChanges都可以拿到ActivityPluginBinding的binding,binding调用getActivity就是了。
226 |
227 | ```java
228 |
229 | public class DemoPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
230 |
231 | static Context ctx;
232 | static Activity activity;
233 |
234 | @Override
235 | public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
236 | ctx = binding.getApplicationContext();
237 | }
238 |
239 | @Override
240 | public void onAttachedToActivity(ActivityPluginBinding binding) {
241 | activity = binding.getActivity();
242 | ctx = binding.getActivity();
243 | }
244 |
245 | @Override
246 | public void onDetachedFromActivityForConfigChanges() {
247 |
248 | }
249 |
250 | @Override
251 | public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
252 | ctx = binding.getActivity();
253 | activity = binding.getActivity();
254 | }
255 | }
256 | ```
257 |
258 | * 2.PlatformView
259 |
260 | Flutter 中通过 `PlatformView` 可以嵌套原生 `View` 到 `Flutter` UI 中,这里面其实是使用了 `Presentation` + `VirtualDisplay` + `Surface` 等实现的,大致原理就是:
261 |
262 | 使用了类似副屏显示的技术,`VirtualDisplay` 类代表一个虚拟显示器,调用 `DisplayManager` 的 `createVirtualDisplay()` 方法,将虚拟显示器的内容渲染在一个 `Surface` 控件上,然后将 `Surface` 的 id 通知给 Dart,让 engine 绘制时,在内存中找到对应的 `Surface` 画面内存数据,然后绘制出来。**实时控件截图渲染显示技术。**
263 |
264 |
265 |
266 | * 3.Platform Channel
267 |
268 | Flutter 中可以通过 `Platform Channel` 让 Dart 代码和原生代码通信的:
269 |
270 | > - `BasicMessageChannel` :用于传递字符串和半结构化的信息。
271 | > - `MethodChannel` :用于传递方法调用(method invocation)。
272 | > - `EventChanne` l: 用于数据流(event streams)的通信。
273 |
274 | **同时 `Platform Channel` 并非是线程安全的** ,更多详细可查阅闲鱼技术的 [《深入理解Flutter Platform Channel》](https://www.jianshu.com/p/39575a90e820)
275 |
276 | 基础数据类型映射如下:
277 |
278 | 
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 | # 介绍
291 |
292 | * 1.运行模式
293 |
294 | **Flutter 的 Debug 下是 JIT 模式,release下是AOT模式。**
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
--------------------------------------------------------------------------------
/img/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ahyangnb/flutter_interview/5e498c960005b67ba4cee6b398393b6c1bfc5ef8/img/.DS_Store
--------------------------------------------------------------------------------
/img/frameworkAndEngine.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ahyangnb/flutter_interview/5e498c960005b67ba4cee6b398393b6c1bfc5ef8/img/frameworkAndEngine.jpg
--------------------------------------------------------------------------------
/img/huizhi.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ahyangnb/flutter_interview/5e498c960005b67ba4cee6b398393b6c1bfc5ef8/img/huizhi.jpg
--------------------------------------------------------------------------------
/img/left_group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ahyangnb/flutter_interview/5e498c960005b67ba4cee6b398393b6c1bfc5ef8/img/left_group.png
--------------------------------------------------------------------------------
/img/reload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ahyangnb/flutter_interview/5e498c960005b67ba4cee6b398393b6c1bfc5ef8/img/reload.png
--------------------------------------------------------------------------------
/ji-chu/untitled.md:
--------------------------------------------------------------------------------
1 | # Untitled
2 |
3 |
--------------------------------------------------------------------------------