flutter相关Flutter面试题面试题专栏

flutter 面试

2021-11-23  本文已影响0人  齐玉婷

一、flutter启动流程
1.实例化WidgetsFlutterBinding类,
2.创建组件树attachRootWidget(app),
3.启动预热帧scheduleWarnUpFrame()。

void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
    ..attachRootWidget(app)
    ..scheduleWarmUpFrame();
}

1.WidgetsFlutterBinding类继承自BindingBase基类和其它一些特定功能特性类,该类是将基于组件框架的应用程序绑定到Flutter引擎的胶水类,并返回一个WidgetsBinding实例。

BindingBase: 该类是一个抽象类基类,初始化拓展服务,其申明的接口由其子类实现。
-GestureBinding: 该类绑定了手势事件,用于检测应用程序各类手势。它以mixin的方式加入到WidgetsFlutterBinding中,并实现了BindingBase类中的部分方法。
-ServicesBinding:该类监听了平台消息(platform messages),注册了Flutter层与Native层的消息传输服务,最终将消息定向到BinaryMessages类中。
-SchedulerBinding: 该类注册了页面帧绘制有关的回调函数,同时也处理Widget生命周期相关事件,处理的事件类型包括:paused、resumed、inactive和suspending。
-PaintingBinding:绑定绘制库,同时还创建了图片缓存。
-SemanticsBinding:将组件语义树与Flutter引擎绑定
-RendererBinding:将组件渲染树与Flutter引擎绑定
-WidgetsBinding:将组件树与Flutter引擎绑定

2.attachRootWidget(Widget rootWidget)函数

void attachRootWidget(Widget rootWidget) {
    _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
      container: renderView,
      debugShortDescription: '[root]',
      child: rootWidget,
    ).attachToRenderTree(buildOwner, renderViewElement);
  }

该函数调用RenderObjectToWidgetAdapter函数创建了一个RenderBox,紧接着将改组件作为根节点并调用attachToRenderTree把组件绑定到Widget树中。

3.scheduleForcedFrame()函数
该函数作用是在App启动是尽快运行预热帧,而不是等待引擎请求帧以响应系统“Vsync”信号。

二、异步
可以使我们在编写Dart程序时可以异步的来执行耗时操作。从而可以在等待一个操作完成的同时进行别的操作以下是一些常见的异步操作:

通过网络获取数据。

写入数据库。

从文件读取数据。

要在Dart中执行异步操作,可以使用Future类和async和await关键字。
1.dart 事件队列

Dart的事件循环(event loop)

在Dart中,实际上有两种队列:

a.用来处理外部的事件,如果IO、点击、绘制、计时器(timer)和不同 isolate 之间的消息事件等。。

将任务添加到MicroTask队列有两种方法

import  'dart:async';
 
void  myTask(){
    print("this is my task");
}
 
void  main() {
    # 1. 使用 scheduleMicrotask 方法添加
    scheduleMicrotask(myTask);
 
    # 2. 使用Future对象添加
    new  Future.microtask(myTask);
}

b.微任务队列(microtask queue),处理来自于Dart内部的任务,适合用来不会特别耗时或紧急的任务。表示一个短时间内就会完成的异步任务。它的优先级最高,高于event queue,只要队列中还有任务,就可以一直霸占着事件循环。microtask queue添加的任务主要是由 Dart内部产生。

在每一次事件循环中,Dart总是先去第一个microtask queue中查询是否有可执行的任务,如果没有,才会处理后续的event queue的流程。异步任务我们用的最多的还是优先级更低的 event queue。Dart为 event queue 的任务建立提供了一层封装,就是我们在Dart中经常用到的Future。

事件循环的运行机制:当应用启动后,它会创建一个isolate,启动事件循环,按照FIFO的顺序,优先处理微任务队列,然后再处理事件队列,如此反复。

三、多线程

注:以下当我们提到isolate的时候,你可以把它等同于线程,但我们知道它不仅仅是一个线程。
1.Isolate
2.compute

1.Isolate
得益于异步 IO + 事件循环,尽管Dart是单线程,一般的IO密集型App应用通常也能获得出色的性能表现。但对于一些计算量巨大的场景,比如图片处理、反序列化、文件压缩这些计算密集型的操作,只单靠一个线程就不够用了。

在Dart中,你可以通过Isolate.spawn 来创建一个新的isolate:

void newIsolate(String mainMessage){
  sleep(Duration(seconds: 3));
  print(mainMessage);
}

void main() {
  // 创建一个新的isolate,newIoslate
  Isolate.spawn(newIsolate, 'Hello, Im from new isolate!'); 
  sleep(Duration(seconds: 10)); //主线程阻塞等待
}

输出:

Hello, Im from new isolate!

spawn 有两个必传参数,第一个是新isolate入口函数(entrypoint),第二个是这个入口函数的参数值(message)。

如果主isolate想接收子isolate的消息,可以在主isolate创建一个ReceivePort对象,并把对应的receivePort.sendPort作为新isolate入口函数参数传入,然后通过ReceivePort绑定SendPort对象给主isolate发送消息:

//新isolate入口函数
void newIsolate(SendPort sendPort){
  sendPort.send("hello, Im from new isolate!");
}

void main() async{
  ReceivePort receivePort= ReceivePort();
  Isolate isolate = await Isolate.spawn(newIsolate, receivePort.sendPort);
  receivePort.listen((message){ //监听从新isolate发送过来的消息
   
    print(message);
     
    // 不再使用时,关闭管道
     receivePort.close();
     
    // 关闭isolate线程
     isolate?.kill(priority: Isolate.immediate);
  });
}
输出:

hello, Im from new isolate!

上面我们了解了主isolate是如何监听来自子isolate的消息的,如果同时子isolate也想知道主isolate的一些状态,那该如何处理呢?下面的代码将提供一种双向通信的方式:

Future<SendPort> initIsolate() async {
  Completer completer = new Completer<SendPort>();
  ReceivePort isolateToMainStream = ReceivePort();

  //监听来自子线程的消息
  isolateToMainStream.listen((data) {
    if (data is SendPort) {
      SendPort mainToIsolateStream = data;
      completer.complete(mainToIsolateStream);
    } else {
      print('[isolateToMainStream] $data');
    }
  });

  Isolate myIsolateInstance = await Isolate.spawn(newIsolate, isolateToMainStream.sendPort);
  //返回来自子isolate的sendPort
  return completer.future; 
}

void newIsolate(SendPort isolateToMainStream) {
  ReceivePort mainToIsolateStream = ReceivePort();
  //关键实现:把SendPort对象传回给主isolate
  isolateToMainStream.send(mainToIsolateStream.sendPort);

  //监听来自主isolate的消息
  mainToIsolateStream.listen((data) {
    print('[mainToIsolateStream] $data');
  });

  isolateToMainStream.send('This is from new isolate');
}

void main() async{
  SendPort mainToIsolate = await initIsolate();
  mainToIsolate.send('This is from main isolate');
}
输出:

[mainToIsolateStream] This is from main isolatemain end
[isolateToMainStream] This is from new isolate

2.compute
你还可以通过一个简化版的compute函数启动一个新的isolate。

比如在反序列化的场景中,直接在主isolate进行序列化:

List<Photo> parsePhotos(String responseBody) {
  final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();

  return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}

Future<List<Photo>> fetchPhotos(http.Client client) async {
  final response =
      await client.get('https://jsonplaceholder.typicode.com/photos');
  //直接在主isolate转换
  return parsePhotos(response.body); 
}

启动一个新的isolate:

Future<List<Photo>> fetchPhotos(http.Client client) async {
  final response =
      await client.get('https://jsonplaceholder.typicode.com/photos');
  // 使用compute函数,启动一个新的isolate
  return compute(parsePhotos, response.body);
}

总结一下,当遇到计算密集型的耗时操作,你可以开启一个新的isolate来并发执行任务。不像我们常规认识的多线程,不同的isolate之间不能共享内存,但通过ReceivePort和SendPort可以构建不同isolate之间的消息通道,另外从别的isolate传来的消息也是要经过事件循环的。

四、Future 说一下 Future?

Future,字面意思「未来」,是用来处理异步的工具。

刚才也说过:

Dart 在单线程中是以消息循环机制来运行的,其中包含两个任务队列,一个是“微任务队列” microtask queue,另一个叫做“事件队列” event queue。

Future 默认情况下其实就是往「事件队列」里插入一个事件,当有空余时间的时候就去执行,当执行完毕后会回调 Future.then(v) 方法。

而我们也可以通过使用 Future.microtask 方法来向 「微任务队列」中插入一个任务,这样就会提高他执行的效率。

因为在 Dart 每一个 isolate 当中,执行优先级为 : Main > MicroTask > EventQueue

五、steam 说一下 Stream?
应用场景:网络状态的监控
Stream 和 Feature 一样,都是用来处理异步的工具。

但是 Stream 和 Feature 不同的地方是 Stream 可以接收多个异步结果,而Feature 只有一个。

Stream 的创建可以使用 Stream.fromFuture,也可以使用 StreamController 来创建和控制。

还有一个注意点是:普通的 Stream 只可以有一个订阅者,如果想要多订阅的话,要使用 asBroadcastStream()。

六、说一下 mixin?
首先mixin是一个定义类的关键字。直译出来是混入,混合的意思 Dart为了支持多重继承,引入了mixin关键字,它最大的特殊处在于: mixin定义的类不能有构造方法,这样可以避免继承多个类而产生的父类构造方法冲突
mixin extends implement 之间的关系?
继承(关键字 extends)、混入 mixins (关键字 with)、接口实现(关键字 implements)。这三者可以同时存在,前后顺序是extends -> mixins -> implements。

Flutter中的继承是单继承,子类重写超类的方法要用@Override,子类调用超类的方法要用super。

在Flutter中,Mixins是一种在多个类层次结构中复用类代码的方法。mixins的对象是类,mixins绝不是继承,也不是接口,而是一种全新的特性,可以mixins多个类,mixins的使用需要满足一定条件。

(1) 使用mixins的条件是什么?
因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.1中使用mixins的条件:

mixins类只能继承自object
mixins类不能有构造函数
一个类可以mixins多个mixins类
可以mixins多个类,不破坏Flutter的单继承

(2) mixin 怎么指定异常类型?
on关键字可用于指定异常类型。 on只能用于被mixins标记的类,例如mixins X on A,意思是要mixins X的话,得先接口实现或者继承A。这里A可以是类,也可以是接口,但是在mixins的时候用法有区别.

七、StatefulWidget 的生命周期
initState():Widget 初始化当前 State,在当前方法中是不能获取到 Context 的,如想获取,可以试试 Future.delayed()
didChangeDependencies():在 initState() 后调用,State对象依赖关系发生变化的时候也会调用。
deactivate():当 State 被暂时从视图树中移除时会调用这个方法,页面切换时也会调用该方法,和Android里的 onPause 差不多。
dispose():Widget 销毁时调用。
didUpdateWidget:Widget 状态发生变化的时候调用。

八、Flutter 如何与 Android iOS 通信?
Flutter 通过 PlatformChannel 与原生进行交互,其中 PlatformChannel 分为三种:

BasicMessageChannel:用于传递字符串和半结构化的信息。
MethodChannel:用于传递方法调用。Flutter主动调用Native的方法,并获取相应的返回值。
EventChannel:用于数据流(event streams)的通信。
具体可以查看 闲鱼技术:深入理解 Flutter Platform Channel。

九、什么是 Widgets、RenderObjects 和 Elements?

Widget 仅用于存储渲染所需要的信息。
RenderObject 负责管理布局、绘制等操作。
Element 才是这颗巨大的控件树上的实体。
具体可以查看[译] Flutter,什么是 Widgets、RenderObjects 和 Elements?

Widget实际上就是Element的配置数据,Widget树实际上是一个配置树,而真正的UI渲染树是由Element构成;不过,由于Element是通过Widget生成,所以它们之间有对应关系,所以在大多数场景,我们可以宽泛地认为Widget树就是指UI控件树或UI渲染树。
一个Widget对象可以对应多个Element对象。这很好理解,根据同一份配置(Widget),可以创建多个实例(Element)。

十、说一下什么是状态管理,为什么需要它?

首先状态其实是一个概念上的东西,区分全局状态和局部状态。

局部状态比如说一个控件中输入的信息,全局状态比如是登陆后从后台请求回来的 userId。

当全局状态越来越多,多个页面共享一个状态时,我们就需要管理它。

常用的状态管理有:

ScopedModel
BLoC
Redux / FishRedux
Provider

十一、说一下 BLoC 模式?
具体可以查看: Vadaski - Flutter | 状态管理探索篇——BLoC(三)

BLoC是一种利用reactive programming方式构建应用的方法,这是一个由流构成的完全异步的世界。

Bloc

十一、如何统一管理错误页面?

我们都知道,如果在 Flutter 当中出错的话,那就是一片红。
可以使用 ErrorWidget.builder 来自定义一个 Widget 就 ok 了。

十二、Stateless Widget和Stateful Widget区别
Stateless Widget和Stateful Widget区别
StatelessWidget用于不需要维护状态的场景.,StatefulWidget用于状态会发生变化的场景,它们都继承自Widget

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

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

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

StatefulElement 间接继承自Element类,与StatefulWidget相对应(作为其配置数据)。StatefulElement中可能会多次调用createState()来创建状态(State)对象。
createState() 用于创建和Stateful widget相关的状态,它在Stateful widget的生命周期中可能会被多次调用。例如,当一个Stateful widget同时插入到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();
}

State生命周期
一个StatefulWidget类会对应一个State类,State表示与其对应的StatefulWidget要维护的状态,

initState()
界面初始化状态时调用

didChangeDependencies()
当state状态对象发生变化时调用(典型的场景是当系统语言Locale或应用主题改变时,Flutter framework会通知widget调用此回调。)

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

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

didUpdateWidget()
用于更新widget ,Widget.canUpdate返回true则会调用此回调

deactivate()
从widget树中移除State对象t时调用(位置交换)

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

十三、为什么第一个Flutter应用构建需要这么长时间?
首次构建Flutter应用时, 将花费更长的时间。这是因为Flutter构建了设备专用的APK或IPA文件。因此, Gradle和Xcode用于构建文件, 需要很长时间。

对象锁和类锁

dart是值传递还是引用传递

await for使用

十四、使用mixins的条件是什么?

因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.1中使用mixins的条件:

mixins类只能继承自object

mixins类不能有构造函数

一个类可以mixins多个mixins类

可以mixins多个类,不破坏Flutter的单继承

十五、Future和Isolate有什么区别?

future是异步编程,调用本身立即返回,并在稍后的某个时候执行完成时再获得返回结果。在普通代码中可以使用await 等待一个异步调用结束。

isolate是并发编程,Dartm有并发时的共享状态,所有Dart代码都在isolate中运行,包括最初的main()。每个isolate都有它自己的堆内存,意味着其中所有内存数据,包括全局数据,都仅对该isolate可见,它们之间的通信只能通过传递消息的机制完成,消息则通过端口(port)收发。isolate只是一个概念,具体取决于如何实现,比如在Dart VM中一个isolate可能会是一个线程,在Web中可能会是一个Web Worker。

十六、Flutter中的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。

这些状态的引入,主要是为了解决多个部件之间的交互和部件自身状态的维护。

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

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

十八、简述Flutter的线程管理模型

默认情况下,Flutter Engine层会创建一个Isolate,并且Dart代码默认就运行在这个主Isolate上。必要时可以使用spawnUri和spawn两种方式来创建新的Isolate,在Flutter中,新创建的Isolate由Flutter进行统一的管理。

事实上,Flutter Engine自己不创建和管理线程,Flutter Engine线程的创建和管理是Embeder负责的,Embeder指的是将引擎移植到平台的中间层代码,Flutter Engine层的架构示意图如下图所示。


截屏2021-11-18 上午10.22.00.png

Flutter的架构中,Embeder提供四个Task Runner,分别是Platform Task Runner、UI Task Runner Thread、GPU Task Runner和IO Task Runner,每个Task Runner负责不同的任务,Flutter Engine不在乎Task Runner运行在哪个线程,但是它需要线程在整个生命周期里面保持稳定。

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

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

优点

热重载(Hot Reload),利用Android Studio直接一个ctrl+s就可以保存并重载,模拟器立马就可以看见效果,相比原生冗长的编译过程强很多;

一切皆为Widget的理念,对于Flutter来说,手机应用里的所有东西都是Widget,通过可组合的空间集合、丰富的动画库以及分层课扩展的架构实现了富有感染力的灵活界面设计;

借助可移植的GPU加速的渲染引擎以及高性能本地代码运行时以达到跨平台设备的高质量用户体验。简单来说就是:最终结果就是利用Flutter构建的应用在运行效率上会和原生应用差不多。

缺点

不支持热更新;

三方库有限,需要自己造轮子;

Dart语言编写,增加了学习难度,并且学习了Dart之后无其他用处,相比JS和Java来说。

二十、 介绍下Flutter的理念架构

截屏2021-11-18 上午10.23.27.png

由上图可知,Flutter框架自下而上分为Embedder、Engine和Framework三层。其中,Embedder是操作系统适配层,实现了渲染

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

二十一、介绍下FFlutter的FrameWork层和Engine层,以及它们的作用

Flutter的FrameWork层是用Drat编写的框架(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小很多。

二十二、 简述Flutter 的热重载

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

热重载的流程可以分为

5 步,包括:扫描工程改动、增量编译、推送更新、代码合并、Widget 重建。Flutter 在接收到代码变更后,并不会让 App

重新启动执行,而只会触发 Widget 树的重新绘制,因此可以保持改动前的状态,大大缩短了从代码修改到看到修改产生的变化之间所需要的时间。

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

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

二十三、简述Flutter的绘制流程

截屏2021-11-18 上午10.26.15.png

Flutter只关心向

GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在

GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为 GPU数据,这些数据通过 OpenGL或者 Vulkan提供给 GPU。

二十四、dart是值传递还是引用传递?

首先给个结论,dart是值传递。我们每次调用函数,传递过去的都是对象的内存地址,而不是这个对象的复制。
我们只要记住一点,参数是把内存地址传过去了,如果对这个内存地址上的对象修改,那么其他位置的引用该内存地址的变量值也会修改。千万要记住dart中一切都是对象。

二十五、flutter特性
Flutter 是 Google 推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart 语言开发 App,一套代码同时运行在 iOS 和 Android平台。 Flutter 提供了丰富的组件、接口,开发者可以很快地为 Flutter 添加 Native 扩展。

》高性能

Flutter 高性能主要靠两点来保证:

第一:Flutter APP 采用 Dart 语言开发。Dart 在 JIT(即时编译)模式下,执行速度与 JavaScript 基本持平。但是 Dart 支持 AOT,当以 AOT模式运行时,JavaScript 便远远追不上了。执行速度的提升对高帧率下的视图数据计算很有帮助。

第二:Flutter 使用自己的渲染引擎来绘制 UI ,布局数据等由 Dart 语言直接控制,所以在布局过程中不需要像 RN 那样要在 JavaScript 和 Native 之间通信,这在一些滑动和拖动的场景下具有明显优势,因为在滑动和拖动过程往往都会引起布局发生变化,所以 JavaScript 需要和 Native 之间不停的同步布局信息,这和在浏览器中JavaScript 频繁操作 DOM 所带来的问题是类似的,都会导致比较可观的性能开销。

》效率高

Dart 运行时和编译器支持 Flutter 的两个关键特性的组合:

基于 JIT 的快速开发周期:Flutter 在开发阶段采用,采用 JIT 模式,这样就避免了每次改动都要进行编译,极大的节省了开发时间;

基于 AOT 的发布包: Flutter 在发布时可以通过 AOT 生成高效的机器码以保证应用性能。而 JavaScript 则不具有这个能力。

二十六、PlatformView
platform view 就是 AndroidView 和 UIKitView 的总称,允许将 native view 嵌入到了 flutter widget 体系中,完成 Datr 代码对 native view 的控制。
https://www.cnblogs.com/ClientInfra/articles/15248565.html(原理)
二十七、flutter从加载到显示
https://mp.weixin.qq.com/s/ncViI0KGikPUIZ7BlEHGOA

main是的作用及调用时机
flutter为什么既要支持运行时编译又要支持运行前编译
dart传参的基本方式
都了解过哪些跨平台技术并聊一下其优缺点
Flutter生命周期介绍
说一下你了解的一些dart语法规范
js了解多少
final与const区别,
with关键字的作用
?、??、??=三者的区别
如何捕捉异常,同步异步
Map如何转Modal
stateless和stateful的区别,为什么根Widget要使用stateless,
如何在启动图消失之前初始化信息
Provider的使用,
使用GestureDetector碰到的坑
flutter的两种路由方式
如何使用Controller调用子节点的方法
动画及自定义动画
让你影响深刻的一些坑及填坑经验
如何做全局路由
flutter项目如何抓包
聊一聊flutterboost的使用场景
如何将Flutter 模块嵌入纯Native项目,及都需要注意哪些事项
如何维护一个路由栈
说下Widgets、RenderObjects 和 Elements的关系
Flutter 是如何与原生Android、iOS进行通信的?
设计一个日志系统,
flutter项目的性能优化
Flutter里的各种key
了解过持续化集成不
设计一个性能监控系统
flutter的通信原理
flutter渲染原理
事件循环
widget的root节点
mixin extends implement之间的关系(除了extends其他的没怎么用过。。)
jvm内存模型(感觉这个是面试官可怜我,看我什么都不会才问的=。=)
介绍下inheritwidget
flutter中都有哪几种线程?
Platform Task Runner
UI Task Runner
GPU Task Runner
IO Task Runner
什么是状态管理,了解哪些状态管理框架
如何在flutter中使用rootBundle加载图像?
如何取消Future.delayed函数调用
Provider.of(context,listen:false)是否等同于context.read()?
如何制作一个ListView.builder从一个特定的索引开始
初始化Dart VM时Flutter应用程序出现错误:错误的完整快照版本,预期为“ 8343…”发现为“ 46b2…”
从Firebase Datasnapshot获取JSON密钥值
Flutter:如何将变量从StatelessWidget传递到StatefulWidget

什么是flutter里的key? 有什么用?
key是Widgets,Elements和SemanticsNodes的标识符。

key有LocalKey 和 GlobalKey两种。

LocalKey 如果要修改集合中的控件的顺序或数量。GlobalKey允许 Widget 在应用中的任何位置更改父级而不会丢失 State。

在什么场景下使用profile mode?
profile model 是用来评估app性能的,profile model 和release mode是相似的,只有保留了一些需要评估app性能的debug功能。在模拟器上profile model是不可用的。

怎么做到只在debug mode运行代码?
foundation有一个静态的变量kReleaseMode来表示是否是release mode

Dart的一些重要概念?
在Dart中,一切都是对象,所有的对象都是继承自Object
Dart是强类型语言,但可以用var或 dynamic来声明一个变量,Dart会自动推断其数据类型,dynamic类似c#
没有赋初值的变量都会有默认值null
Dart支持顶层方法,如main方法,可以在方法内部创建方法
Dart支持顶层变量,也支持类变量或对象变量
Dart没有public protected private等关键字,如果某个变量以下划线(_)开头,代表这个变量在库中是私有的

上一篇下一篇

猜你喜欢

热点阅读