当前位置: 首页 > article >正文

flutter常见面试题(欢迎私信投稿——更新到10)

1、谈谈Flutter中的Future、async和await

Future对象表示异步操作的结果,我们通常通过then()来处理返回的结果
async用于标明函数是一个异步函数,其返回值类型是Future类型
await用来等待耗时操作的返回结果,这个操作会阻塞到后面的代码
isolate异步并行多个任务,Future是异步串行多个任务

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、举几个提升flutter性能的方法

在 Flutter 中,提升性能有多种方法:

- 减少不必要的Widget重建

- 使用const关键字:对于不会改变的Widget,用 const 修饰。像 const Text('固定文本') ,这样Flutter就知道该Widget无需重建,能节省资源,因为它被视为编译时常量,在多处复用也不产生额外开销 。

- 使用StatefulWidget恰当:无状态改变需求时,别用 StatefulWidget 。例如简单展示静态文本, StatelessWidget 足够,避免多余的状态管理开销。另外,拆分 StatefulWidget 为更细粒度的组件,只让真正需要更新状态的部分成为 Stateful ,限制重建范围。

- 使用Key精准控制:当Widget树里相同类型Widget位置更替,给它们添加唯一 Key 。如 ListView 动态增删item,合适的 Key 能让Flutter精准定位变化,而非大规模重建。

- 优化布局

- 避免嵌套过深:多层嵌套的 Column 、 Row 、 Padding 等组件会拖慢渲染。可以用 Flex 组件灵活排版,减少嵌套层级;或是使用 CustomMultiChildLayout 来自定义布局,提升布局效率。

- 使用SizedBox.shrink():当想让某个Widget占最小空间,优先用它替代 Container 设置 width/height 为0, SizedBox.shrink() 没有额外绘制负担。

- 图片处理

- 压缩图片资源:上传前在本地压缩图片,或使用网络图片时,选择合适尺寸,防止加载超大图拖慢加载速度与内存占用。

- 使用合适的图片缓存:Flutter默认有图片缓存机制,也可以借助第三方库如 cached_network_image ,合理设置缓存时长与大小,减少重复网络请求。

- 异步操作优化

- 高效处理网络请求:使用如 dio 这类网络库时,批量发起请求、合理设置超时时间,利用异步编程避免阻塞主线程。在等待网络响应时,主线程还能处理UI交互,维持流畅性。

- 后台任务调度:耗时的计算任务放到后台线程执行,Flutter里能借助 compute 函数,把CPU密集型运算放到独立的Isolate(类似线程但更安全)处理,处理完再更新UI。

- 内存管理

- 及时释放资源:监听 State 的 dispose 生命周期方法,及时清理定时器、流订阅、动画控制器等,防止内存泄漏。比如取消网络请求、关闭文件流,让不再使用的对象能被垃圾回收。

- 优化数据存储:大量数据存储在内存时,考虑分页加载,而非一次性加载海量数据。像长列表场景,只加载屏幕内及附近少量item,滚动时动态更新。

4、Widget的StatelessWidget和StatefulWidget两种状态组件类

StatelessWidget: 创建以后不去关心任何变化,在下次构建之前都不会改变。它们除了依赖于自身的配置信息(在父节点构建时提供)外不再依赖于任何其他信息。比如典型的Text、Row、Column、Container等,都是StatelessWidget。它的生命周期简单:初始化、通过build()渲染。

StatefulWidget: 在生命周期内,这种类型的Widget所持有的数据可能会发生变化,这样的数据被称为State,这些拥有动态内部数据的Widget被称为StatefulWidget。比如复选框、Button等。State会与Context永久的建立关联并且不会改变Context。     当state与context关联时,state被视为已挂载。StatefulWidget由两部分组成,在初始化时必须要在createState()时初始化一个与之相关的State对象。

5、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 状态发生变化的时候调用。

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


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

BasicMessageChannel :用于传递字符串和半结构化的信息。

MethodChannel :用于传递方法调用(method invocation)。

EventChannel : 用于数据流(event streams)的通信。

7、简述Flutter 的热重载?


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

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

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

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

8、Stream数据流?

在Dart中,Stream 和 Future 一样,都是用来处理异步编程的工具。它们的区别在于,Stream 可以接收多个异步结果,而Future 只有一个。
Stream 的创建可以使用 Stream.fromFuture,也可以使用 StreamController 来创建和控制。还有一个注意点是:普通的 Stream 只可以有一个订阅者,如果想要多订阅的话,要使用 asBroadcastStream()。

9、runApp()和main()有什么区别?

main()是任何Dart或Flutter应用程序的入口点。这是应用程序启动时执行的第一个函数。

runApp()是由Flutter框架提供的函数。它的主要目的是将Flutter应用程序的根小部件附加到屏幕上。

final是运行时常量,值在运行时赋值;const是编译期常量,值在编译时赋值;

10、Fultter如何发起网络请求?常用那些库?

使用的http库(Dart原生)

步骤一:添加依赖

pubspec.yaml文件中添加http库的依赖。http是 Dart 语言的一个网络请求库,在 Flutter 项目中也可以很好地使用。

步骤二:发起请求

例如,发起一个简单的 GET 请求来获取一些数据。首先需要导入http库:

在上述代码中,Uri.parse()方法用于将一个字符串形式的 URL 转换为Uri对象,这是http库中请求方法所要求的参数格式。await关键字用于等待异步操作(网络请求)完成。response.statusCode用于获取请求的状态码,response.body用于获取服务器返回的数据内容。

 dio库

步骤一:添加依赖

  • pubspec.yaml文件中添加dio库的依赖。dio是一个强大的 Dart HTTP 请求库,支持多种请求方式、拦截器等功能。

同样需要运行flutter pub get来获取该依赖。

步骤二:发起请求

首先导入dio库:

Dio类的实例用于管理请求。dio.get()方法用于发起 GET 请求,它会返回一个包含服务器响应数据的对象。如果请求过程中出现错误,会被catch块捕获并打印错误信息。

  1. 常用网络请求库

    1. http

特点它是 Dart 原生的网络请求库,简单易用,对于基本的网络请求操作(如 GET、POST 等)很方便。它的 API 相对简洁,学习成本较低,适合初学者或者只需要进行简单网络通信的场景。

适用场景简单的数据获取,例如从一个提供公开 API 的服务器获取一些配置信息、新闻列表等。或者用于向服务器发送简单的表单数据,如用户登录(POST 请求用户名和密码)等基础操作。

  1. dio

特点功能强大,支持多种请求方法(GET、POST、PUT、DELETE 等)。它具有拦截器功能,可以在请求发送前和响应返回后进行统一的处理,比如添加请求头、处理错误、日志记录等。dio还支持文件上传和下载,并且可以方便地配置请求的超时时间等参数。

适用场景适用于复杂的网络请求场景,比如需要在多个请求中添加统一的认证头信息,或者需要对请求和响应进行详细的日志记录。在进行文件上传(如用户头像上传)和下载(如下载应用更新文件)时也非常方便。同时,对于大型项目,需要对网络请求进行统一管理和错误处理时,dio是一个很好的选择。

  1. Chopper

特点Chopper是一个基于 Dart 的 HTTP 客户端生成器,它使用代码生成来提供类型安全的 API。它允许通过定义服务接口来生成网络请求相关的代码,这样可以减少手动编写网络请求代码的工作量,并且在编译时可以发现一些错误。

适用场景适合在大型项目中,对代码的规范性和可维护性要求较高的场景。例如,当有多个不同的 API 端点需要调用,并且希望通过接口的方式来清晰地定义每个端点的请求和响应格式,Chopper可以帮助生成类型安全的网络请求代码,提高代码的可读性和可维护性。


http://www.kler.cn/a/546662.html

相关文章:

  • 华为手机鸿蒙4回退到鸿蒙3到鸿蒙2再回退到EMUI11 最后关闭系统更新
  • 独立C++ asio库实现的UDP Client
  • 鸿蒙Next开发-添加水印以及点击穿透设置
  • 在带有Intel NPU的Windows上安装IPEX-LLM
  • RadASM环境,win32汇编入门教程之三
  • 基于Ceedling的嵌入式软件单元测试
  • 数字图像基础:像素、分辨率、灰度图像与彩色图像
  • 【代码随想录】刷题记录(115)-岛屿数量(广搜)
  • Vue3 从入门到精通:全面掌握前端框架的进阶之路
  • Java 设计模式之组合模式
  • Windows 图形显示驱动开发-WDDM 2.0 -Gpu段
  • 云计算——ACA学习 云计算分类
  • ESP学习-1(MicroPython VSCode开发环境搭建)
  • Redis——优惠券秒杀问题(分布式id、一人多单超卖、乐悲锁、CAS、分布式锁、Redisson)
  • 百度宣布:免费!
  • Next.js【详解】CSS 样式方案
  • 【MySQL — 数据库基础】深入解析 MySQL 的联合查询
  • 支付宝 IoT 设备入门宝典(上)设备管理篇
  • 20250214 随笔 Nginx 负载均衡在数据库中的应用
  • JavaScript + HTML5 Canvas 实现互动爱心雨