29个Flutter面试问题移动开发人员需要知道的
作为下一轮革命,Flutter正在移动市场中蓬勃发展。事实证明,它具有赢得所有移动技术的潜力,并成为未来跨平台应用程序开发的唯一选择。跟随并检查第一个最全面的Flutter面试问答列表,该列表将在2020年的移动开发人员面试中发展。FullStack.Cafe独家提供。
最初发布在FullStack.Cafe-开发人员的真实技术面试问答
Q1:什么是Flutter?
主题:颤振
难度:⭐
Flutter是Google提供的一个开源UI工具包,用于通过单个代码库为桌面,Web和移动设备制作精美的,本机编译的应用程序。 Flutter应用是使用Dart编程语言构建的。
?资料来源:flutter.dev
Q2:什么是Dart?为什么Flutter使用它?
主题:颤振
难度:⭐⭐
Dart是一种面向对象的垃圾收集编程语言,可用于开发Flutter应用程序。
它也是由Google创建的,但是是开源的,并且在Google内部和外部都有社区。
由于以下原因,Dart被选为Flutter的语言:
- Dart是AOT(提前时间)编译为快速,可预测的本机代码,几乎所有Flutter都可以用Dart编写。这不仅使Flutter更快,而且几乎所有内容(包括所有小部件)都可以自定义。
- Dart还可以通过JIT(Just In Time)进行编译,以实现异常快速的开发周期和改变游戏规则的工作流程(包括Flutter流行的亚秒级有状态热重装)。
- Dart允许Flutter避免使用像JSX或XML这样的声明式布局语言,也不需要单独的可视界面构建器,因为Dart的声明式程序化布局易于阅读和可视化。而且,由于所有布局都以一种语言和一种位置显示,因此Flutter可以轻松地提供使布局变得轻松的高级工具。
?资料来源:hackernoon.com
Q3:什么是“小部件”并在Flutter中提及其重要性?
主题:颤振
难度:⭐⭐
- 小部件基本上是Flutter中的UI组件。
- 这是描述元素配置的一种方式。
- 它们是受React中组件启发的。
小部件在Flutter中很重要,因为Flutter应用程序中的所有内容都是小部件,从简单的“文本”到“按钮”再到“屏幕布局”。
?资料来源:stackoverflow.com
Q4:Flutter中有几种类型的小部件?
主题:颤振
难度:⭐⭐
有两种类型的小部件:
- StatelessWidget:不需要可变状态的小部件。
- StatefulWidget:具有可变状态的小部件。
?资料来源:proandroiddev.com
Q5:Flutter中的“ main()”和“ runApp()”函数有什么区别?
主题:颤振
难度:⭐⭐
-
main ()
函数来自类似Java的语言,因此它是所有程序启动的地方,没有它,即使没有UI也无法在Flutter上编写任何程序。 -
runApp()
函数应返回将附加到屏幕上的小部件,作为将要呈现的小部件树的根。
?资料来源:stackoverflow.com
Q6:什么是应用程序状态?
主题:颤振
难度:⭐⭐
- 非短暂状态,您要在应用程序的许多部分之间共享,以及希望在用户会话之间保持的状态,就是我们所说的应用程序状态(有时也称为共享状态)。
- 应用状态示例:
- 用户偏好
- 登录信息
- 社交网络应用中的通知
- 电子商务应用程序中的购物车
- 新闻应用中文章的已读/未读状态
?资料来源:flutter.dev
Q7:Flutter中有哪些不同的构建模式?
主题:颤振
难度:⭐⭐
- Flutter工具在编译应用程序时支持三种模式,以及用于测试的无头模式。
- 您可以根据您在开发周期中的位置来选择编译模式。
- 这些模式是:
- 除错
- 轮廓
- 发布
?资料来源:flutter.dev
Q8:区分StatelessWidget和StatefulWidget?
主题:颤振
难度:⭐⭐⭐
无状态:窗口小部件状态仅创建一次,然后可以更新值,但不能显式声明状态。这就是为什么它只有一个类 StatelessWidget
。他们永远都无法重跑 build()
再次的方法。
有状态的:小部件可以在事件触发后多次更新其STATE(本地)和值。这就是原因,实现方式也有所不同。在这里,我们有2个类,一个是 StatefulWidget
&另一个是状态执行处理程序,即 State
。所以如果我说,他们可以重新运行 build()
再次基于触发的事件进行方法。
- 一种
StatelessWidget
永远不会自行重建(但可以从外部事件重建)。一种StatefulWidget
能够。 - 一种
StatelessWidget
是静态的StatefulWidget
是动态的。
请参见下图:
?资料来源:stackoverflow.com
Q9:为什么我们将函数传递给小部件?
主题:颤振
难度:⭐⭐⭐
- 函数是Dart中的一流对象,可以作为参数传递给其他函数。
- 我们将一个函数传递给一个小部件,本质上说,“发生某些事情时调用此函数”。
- 使用Android(
Java函数是Dart中的一流对象,可以作为参数传递给其他函数。
button.setOnClickListener(new View.OnClickListener() {
@override
public void onClick(View view) {
// Do something here
}
}
);
(请注意,这仅是用于设置侦听器的代码。定义按钮需要单独的XML代码。)
飞镖等效项:
FlatButton(
onPressed: () {
// Do something here
}
)
(Dart同时进行声明和设置回调。)
这变得更加整洁有序,并帮助我们避免不必要的复杂化。
?资料来源:medium.com
Q10:区分热重启和热重启吗?
主题:颤振
难度:⭐⭐⭐
热装
- Flutter热重装功能与命令提示符或终端上的Small r键组合使用。
- 热重装功能可以快速编译文件中新添加的代码,并将代码发送到Dart虚拟机。更新完Code Dart虚拟机后,请使用小部件更新应用程序UI。
- 热重启所需的时间少于热重启所需的时间。
- Hot Reload也有一个缺点,如果您在应用程序中使用状态,则Hot Reload将保留状态,这样它们就不会在Hot Reload上更新为默认值。
热重启
- 热重启与热重新加载有很大不同。
- 在热重启中,它会破坏保留状态值并将其设置为默认值。因此,如果您在应用程序中使用“状态”值,则在每次热重启后,开发人员都会获取完全编译的应用程序,并且所有状态都将设置为其默认值。
- 应用窗口小部件树已使用新键入的代码完全重建。
- 热重启所需的时间比热重启所需的时间长得多。
?资料来源:https://flutter-examples.com/difference-between-hot-reload-and-hot-restart-in-flutter-dart/
问题11:在Dart中区分必需参数和可选参数吗?
主题:颤振
难度:⭐⭐⭐
必要参数
Dart必需参数是传递给函数的参数,而函数或方法需要所有这些参数来完成其代码块。
findVolume(int length, int breath, int height) {
print('length = $length, breath = $breath, height = $height');
}
findVolume(10,20,30);
可选参数
- 可选参数在任何必需参数之后的参数列表末尾定义。
- 在Flutter / Dart中,有3种可选参数:
- 命名
- 由参数盘点
{ }
- 例如。
getUrl(int color, [int favNum])
- 由参数盘点
- 位置性
- 由参数盘点
[ ]
) - 例如。
getUrl(int color, {int favNum})
- 由参数盘点
- 默认
- 为参数分配默认值。
- 例如。
getUrl(int color, [int favNum = 6])
- 命名
?资料来源:stackoverflow.com
问题12:什么是ScopedModel / BLoC模式?
主题:颤振
难度:⭐⭐⭐
ScopedModel和BLoC(业务逻辑组件)是Flutter应用程序的常见架构模式,可帮助将业务逻辑与UI代码分开,并使用更少的状态控件。
-
范围模型是Flutter框架中未包含的第三方程序包。它是一组实用程序,可让您轻松地将数据模型从父Widget传递到其后代。此外,它还可以在更新模型时重建使用该模型的所有子代。该库最初是从Fuchsia代码库中提取的。
-
BLoC代表业务逻辑组件。它有助于管理状态并从项目的中心位置访问数据。 BLoC的要旨是应将应用程序中的所有内容都表示为事件流:小部件提交事件;其他小部件将响应。 BLoC位于中间,管理对话。
?资料来源:technologymoon.com
Q13:什么是Flutter / Dart中的流?
主题:颤振
难度:⭐⭐⭐
- Dart中的异步编程的特点是
Future
和Stream
类。 - 流是一系列异步事件。这就像一个异步的Iterable,在那里,流告诉您准备就绪时有一个事件,而不是在您请求时获取下一个事件。
-
流可以通过多种方式创建,但是它们的使用方式都相同。异步for循环(等待)。例如
Future<int> sumStream(Stream<int> stream) async { var sum = 0; await for (var value in stream) { sum += value; } return sum; }
-
流提供异步的数据序列。
-
数据序列包括用户生成的事件和从文件读取的数据。
-
您可以使用“等待”或“
listen()
来自Stream API。 -
流提供了一种响应错误的方法。
-
流有两种:单一订阅或广播。
?资料来源:dart.dev
Q14:解释不同类型的流?
主题:颤振
难度:⭐⭐⭐
有两种流。
-
单一订阅流
- 最常见的流。
- 它包含一系列事件,这些事件是一个较大的整体的一部分。事件必须以正确的顺序传递,并且不能丢失任何事件。
- 这是您在读取文件或接收Web请求时获得的流。
- 这样的流只能被收听一次。稍后再次收听可能意味着错过了最初的事件,然后其余部分毫无意义。
- 当您开始侦听时,数据将被提取并以块的形式提供。
- 广播流
- 它用于可一次处理的单个消息。例如,这种流可用于浏览器中的鼠标事件。
- 您可以随时开始收听这样的流,并且在收听时会触发事件。
- 多个收听者可以同时收听,您可以在取消上一个订阅后稍后再次收听。
?资料来源:dart.dev
Q15:什么是Flutter中的软件包和插件?
主题:颤振
难度:⭐⭐⭐
- 包允许您将新的小部件或功能导入到您的应用程序中。
- 包和插件之间有一个很小的区别。
- 软件包通常是纯Dart编写的新组件或代码,而插件可以使用本机代码在设备端实现更多功能。
- 通常在DartPub上,程序包和插件都称为程序包,只有在创建新程序包时才明确提及其区别。
?资料来源:medium.com
Q16:Flutter中的键是什么?何时使用?
主题:颤振
难度:⭐⭐⭐
- 一种
Key
是一个标识符Widgets
,Elements
和SemanticsNodes
。 - 如果新窗口小部件的键与与该元素关联的当前窗口小部件的键相同,则仅将其用于更新现有元素。
- 在具有相同父元素的Elements中,键必须唯一。
- 的子类
Key
应该是子类LocalKey
要么GlobalKey
。 - 在处理相同类型的小部件集合时,键非常有用。
- 如果发现自己添加,删除或重新排序具有某种状态的相同类型的小部件集合,则应使用一个键。
?资料来源:api.flutter.dev
Q17:什么是空感知运算符?
主题:颤振
难度:⭐⭐⭐
- Dart提供了一些方便的运算符来处理可能为null的值。
-
一个是?? =赋值运算符,它仅在该变量当前为null时才为该变量赋值:
int a; // The initial value of a is null. a ??= 3; print(a); // <-- Prints 3. a ??= 5; print(a); // <-- Still prints 3.
-
另一个可识别空值的运算符是??,它会返回左侧的表达式,除非该表达式的值为null,在这种情况下,它会计算并返回其右侧的表达式:
print(1 ?? 3); // <-- Prints 1. print(null ?? 12); // <-- Prints 12.
?资料来源:dart.dev
Q18:什么是配置文件模式,何时使用?
主题:颤振
难度:⭐⭐⭐
- 在配置文件模式下,将保留一些调试功能,足以对应用程序的性能进行配置。
- 要分析性能时,使用概要文件模式。
- 在仿真器和模拟器上禁用了概要文件模式,因为它们的行为不能代表实际性能。
- 在移动设备上,个人资料模式类似于发布模式,但有以下区别:
- 启用了某些服务扩展,例如启用性能覆盖的扩展。
- 启用了跟踪,并且支持源代码级调试的工具(例如DevTools)可以连接到该进程。
- Web应用程序的配置文件模式意味着:
- 构建没有缩小,但是已经执行了摇树操作。
- 该应用程序是使用dart2js编译器进行编译的。
- 命令
flutter run --profile
编译为配置文件模式。
?资料来源:flutter.dev
Q19:什么是发布模式,什么时候使用?
主题:颤振
难度:⭐⭐⭐
- 当需要最大程度的优化和最小的占用空间时,请使用发布模式来部署应用程序。
- 准备发布应用程序时,请使用发布模式。
- 对于移动设备,释放模式(模拟器或模拟器不支持)表示:
- 断言被禁用。
- 调试信息被剥离。
- 调试被禁用。
- 编译针对快速启动,快速执行和小盘点进行了优化。
服务扩展已禁用。
- Web应用程序的发布模式意味着:
- 最小化了构建,并执行了摇树操作。
- 该应用程序使用dart2js编译器进行了编译,以实现最佳性能。
- 命令
flutter run --release
编译为发布模式。 - 您可以使用以下命令编译为特定目标的发布模式
flutter build
。
?资料来源:flutter.dev
问题20:如何仅在调试模式下执行代码?
主题:颤振
难度:⭐⭐⭐
解决方法是:
import 'package:flutter/foundation.dart' as Foundation;
那么你可以使用 kReleaseMode
喜欢
if(Foundation.kReleaseMode){ // is Release Mode ??
print('release mode');
} else {
print('debug mode');
}
?资料来源:stackoverflow.com
Q21:解释异步,在Flutter / Dart中等待吗?
主题:颤振
难度:⭐⭐⭐⭐
异步操作使您的程序可以在等待另一个操作完成的同时完成工作。以下是一些常见的异步操作:
- 通过网络获取数据。
- 写入数据库。
- 从文件读取数据。
要在Dart中执行异步操作,您可以使用 Future
类和 async
和 await
关键字。
的 async
和 await
关键字提供了一种声明性的方式来定义异步函数并使用其结果。使用时请记住这两个基本准则 async
和 await
:
- 要定义异步功能,请添加
async
在功能主体之前 - 的
await
关键字仅在async
功能。
一个 async
功能同步运行,直到第一个 await
关键词。这意味着在 async
函数体,所有同步代码在第一个之前 await
关键字立即执行。
考虑一个例子:
import 'dart:async';
class Employee {
int id;
String firstName;
String lastName;
Employee(this.id, this.firstName, this.lastName);
}
void main() async {
print("getting employee...");
var x = await getEmployee(33);
print("Got back ${x.firstName} ${x.lastName} with id# ${x.id}");
}
Future<Employee> getEmployee(int id) async {
//Simluate what a real service call delay may look like by delaying 2 seconds
await Future<Employee>.delayed(const Duration(seconds: 2));
//and then return an employee - lets pretend we grabbed this out of a database
var e = new Employee(id, "Joe", "Coder");
return e;
}
?资料来源:dart.dev
Q22:Flutter / Dart的未来是什么?
主题:颤振
难度:⭐⭐⭐⭐
-
期货用于表示将来某个时候可用的潜在值或错误。 Future的接收者可以注册一旦值或错误可用的回调。例如:
Future<int> future = getFuture(); future.then((value) => handleValue(value)) .catchError((error) => handleError(error));
-
如果期货无法产生可用价值,那么该期货的类型为
Future
。 -
未来表示异步操作的结果,可以有两种状态:
-
未完成
当您调用异步函数时,它将返回未完成的将来。那个未来正在等待函数的异步操作完成或引发错误。 -
已完成
如果异步操作成功,则将来将以一个值完成。否则,它将以错误完成。
-
?资料来源:api.dart.dev
问题23:Future和Stream有什么异同?
主题:颤振
难度:⭐⭐⭐⭐
相似:
-
Future
和Stream
两者都是异步工作的。 - 两者都有一定的潜在价值。
差异:
- 一种
Stream
是期货的组合。 -
Future
只有一个回应,但Stream
可以有任意数量的响应。
?资料来源:medium.com
Q24:double.INFINITY和MediaQuery有什么区别?
主题:颤振
难度:⭐⭐⭐⭐
区别可以总结为:
- 我想和我父母一样大(
double.INFINITY
) - 我想和屏幕一样大(
MediaQuery
)。
通常,您需要使用 double.infinity
,但并非总是可能的。一些小部件允许他们的孩子像他们想要的一样大(Column
, ListView
, OverflowBox
…)。在那种情况下使用 double.infinity
产生一个悖论:
- 父母允许任何大小
- 孩子想要父母允许的最大尺寸
?资料来源:api.flutter.dev
Q25:Dart AOT如何工作?
主题:颤振
难度:⭐⭐⭐⭐
- Dart源代码将被翻译为汇编文件,然后汇编器将汇编文件编译为用于不同体系结构的二进制代码。
- 对于移动应用程序,源代码针对多个处理器ARM,ARM64,x64以及两个平台(Android和iOS)进行编译。这意味着每种支持的处理器和平台组合都有多个结果二进制文件。
?资料来源:flutterbyexample.com
Q26:这些运算符“?”和“?”之间有什么区别?
主题:颤振
难度:⭐⭐⭐⭐
??
- 这是一个可识别null的运算符,除非该表达式的值为null,否则它将在其左侧返回该表达式,在这种情况下,它将求值并在其右侧返回该表达式:
print(1 ?? 3); // <-- Prints 1.
print(null ?? 12); // <-- Prints 12.
?
- 这是一种条件属性访问,用于保护对可能为空的对象的属性或方法的访问,请在点(。)之前添加问号(?):
-
您可以链接多种用途
?.
在一个表达式中一起:myObject?.someProperty?.someMethod()
前面的代码返回null(并且从不调用
someMethod()
)(如果有)myObject
要么myObject.someProperty
一片空白。
?资料来源:flutter.dev
问题27:列出Flutter中的状态管理方法
主题:颤振
难度:⭐⭐⭐⭐⭐
应用程序的状态是应用程序运行时内存中存在的所有内容。其中包括应用程序的资产,Flutter框架保留的有关UI,动画状态,纹理,字体等的所有变量。
- 颤振框架会自行处理某些状态,例如纹理。
- 我们管理的状态可以分为两种概念类型:
- 暂时状态
- 应用状态
Flutter中状态管理的一些方法是:
setState
-
InheritedWidget
和InheritedModel
- 提供者和范围模型
- Redux
- BLoC /接收
- 手机
?资料来源:flutter.dev
Q28:详细说明有状态小部件生命周期
主题:颤振
难度:⭐⭐⭐⭐⭐
有状态小部件具有以下生命周期阶段:
- createState()
- mounted == true
- initState()
- didChangeDependencies()
- build()
- didUpdateWidget()
- setState()
- deactivate()
- dispose()
- mounted == false
createState()
-
当指示Flutter建立一个
StatefulWidget
,它立即调用createState()
。此方法必须存在。一种StatefulWidget
很少需要比这更复杂。class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => new _MyHomePageState(); }
安装是真的
- 什么时候
createState
创建状态类,一个buildContext
被分配给该状态。 - 一种
BuildContext
被过分简化的是在此小部件中放置在小部件树中的位置。 - 所有小部件都有一个布尔值
this.mounted
属性。当buildContext
被安排了。打电话是错误的setState
卸载小部件时。
initState()
- 这是在创建窗口小部件时调用的第一个方法(当然,在类构造函数之后)。
-
initState
只被调用一次。它也必须super.initState()
。 -
此@override方法是执行以下操作的最佳时间:
- 初始化依赖于特定数据的数据
BuildContext
用于创建的小部件实例。 - 在树中初始化依赖于此小部件“父级”的属性。
-
订阅
Streams
,ChangeNotifiers
,或任何其他可能更改此小部件上的数据的对象。@override initState() { super.initState(); // Add listeners to this class cartItemStream.listen((data) { _updateWidget(data); }); }
- 初始化依赖于特定数据的数据
didChangeDependencies()
- 的
didChangeDependencies
方法在之后立即被调用initState
在第一次构建窗口小部件时。 - 每当调用此小部件依赖于其数据的对象时,也会调用该方法。例如,如果它依赖于
InheritedWidget
,即会更新。 -
build
总是被称为didChangeDependencies
被称为,因此几乎不需要。但是,此方法是您必须调用的第一个更改BuildContext.inheritFromWidgetOfExactType
。从本质上讲,这将使该状态“侦听”从其继承数据的小部件上的更改。 - 该文档还建议,如果您需要在
InheritedWidget
更新。
建立()
- 经常调用此方法(想想fps +渲染)。这是必需的
@override
并且必须返回一个Widget
。 - 请记住,在Flutter中,所有gui都是一个带有一个或多个孩子的小部件,甚至“
Padding
‘,’Center
‘。
didUpdateWidget(Widget oldWidget)
-
didUpdateWidget()
如果父窗口小部件发生更改并且必须重建此窗口小部件(因为需要为其提供不同的数据),则调用该方法,但是使用相同的方法对其进行重建runtimeType
,则调用此方法。 - 这是因为Flutter正在重用长期存在的状态。在这种情况下,所需的是再次初始化一些数据,就像
initState()
。 - 如果国家
build()
方法依赖于Stream
或其他可以更改的对象,请从旧对象中取消订阅,然后重新订阅didUpdateWidget()
。
提示:此方法基本上是“
initState()
‘如果可以预期Widget
与小部件的状态关联的状态需要重新构建
-
颤振总是打电话
build()
在此之后,因此任何后续调用setState
是多余的。@override void didUpdateWidget(Widget oldWidget) { if (oldWidget.importantProperty != widget.importantProperty) { _init(); } }
setState()
- ‘
setState()
通常从Flutter框架本身和开发人员中调用方法。 - 它用于通知框架“数据已更改”,并且应重新构建此构建上下文中的小部件。
-
setState()
接受一个不能异步的回调。因此,可以根据需要经常调用它,因为重涂很便宜void updateProfile(String name) { setState(() => this.name = name); }
停用()
- 这很少使用。
- ‘
deactivate()
当被称为State
已从树中删除,但可能会在当前帧更改完成之前将其重新插入。之所以存在这种方法,基本上是因为State
可以将对象从树中的一个点移动到另一点。
dispose()
- ‘
dispose()
当State
对象被删除,这是永久的。 -
可以取消订阅并取消所有动画,流等的方法。
-
安装错误
-
状态对象永远无法重新挂载,并且会引发错误
setState()
叫做。
?资料来源:flutterbyexample.com
Q29:调试模式和配置文件模式之间有什么区别?
主题:颤振
难度:⭐⭐⭐⭐⭐
调试模式:
- 在开发阶段以及您要使用热重装时使用。
- 默认情况下,
flutter run
编译为调试模式。 - 移动应用程序的调试模式意味着:
- 断言已启用。
- 服务扩展已启用。
- 编译针对快速开发和运行周期进行了优化(但不针对执行速度,二进制大小或部署进行优化)。
- 启用了调试,并且支持源代码级调试的工具(例如DevTools)可以连接到该进程。
- Web应用程序的调试模式意味着:
- 不会缩小版本,也没有执行摇树操作。
- 该应用程序使用dartdevc编译器进行了编译,以便于调试。
个人资料模式:
- 要分析性能时,使用概要文件模式。
- 命令
flutter run --profile
编译为配置文件模式。 - 在仿真器和模拟器上禁用了概要文件模式,因为它们的行为不能代表实际性能。
- 在移动设备上,个人资料模式类似于发布模式,但有以下区别:
- 启用了某些服务扩展,例如启用性能覆盖的扩展。
- 启用了跟踪,并且支持源代码级调试的工具(例如DevTools)可以连接到该进程。
- Web应用程序的配置文件模式意味着:
- 构建没有缩小,但是已经执行了摇树操作。
- 该应用程序是使用dart2js编译器编译的。
?资料来源:flutter.dev
感谢?阅读并祝您面试顺利
如果愿意,请与您的开发人员分享这篇文章
在?www.fullstack.cafe上查看更多FullStack面试问答。