2025-09-15

1. StatelessWidget 和 StatefulWidget在 Flutter 中有什么区别?

StatelessWidget

定义:
StatelessWidget 是一种不可变的 Widget,其状态在创建后不会改变。自己不能更新自己,它们只依赖于构造函数中的参数来构建 UI。

特点:

  • 不维护任何内部状态。
  • 适合用于显示静态内容或简单的 UI 结构。
  • 在需要更新 UI 时,必须重新创建该 Widget 的实例。

StatefulWidget

定义:
StatefulWidget 是一种可变的 Widget,可以在其生命周期内维护状态。它可以响应用户输入或其他事件并更新 UI。

特点:

  • 具有一个可变的状态(通过 State 类管理)。
  • 当状态发生变化时,通过调用 setState() 方法来通知 Flutter 更新 UI。
  • 适合用于需要动态更新的内容,如表单、动画等。

状态管理

  • StatelessWidget:不维护任何状态,适合静态内容。
  • StatefulWidget:可以维护内部状态,适合动态内容。

更新机制

  • StatelessWidget:需要重新创建实例来更新 UI。
  • StatefulWidget:通过 setState() 方法来更新 UI。

根据应用的需求,开发者可以选择使用 StatelessWidget 或 StatefulWidget 来构建相应的界面。

2. 解释 Stateful Widget Lifecycle 生命周期

Stateful Widget 生命周期阶段

State 生命周期(State 类)

State 对象有以下几个生命周期方法,按调用顺序如下:

  1. createState():当 Stateful Widget 被插入到 Widget 树中时,会调用 createState() 方法。这个方法必须返回一个 State 对象。
  2. mounted:在 createState() 之后,State 对象与 BuildContext 关联,此时 mounted 属性被设置为 true。这是一个重要的标志,表示 State 对象当前是否在树中。在调用 setState 时,必须确保 mounted 为 true,否则会抛出异常。
  3. initState():这是 State 对象的初始化方法,在 State 对象被创建后调用,且仅调用一次。通常用于初始化依赖、监听器或接收父 Widget 传递的数据。
  4. didChangeDependencies():在 initState() 之后立即调用,也会在依赖的 InheritedWidget 发生变化时调用。可以在这个方法中执行一些依赖于上下文或 InheritedWidget 的操作。
  5. build():这个方法用于构建 Widget 树。在以下情况会被调用:
    • after initState()
    • after didChangeDependencies()
    • after didUpdateWidget()
    • after setState()
  6. didUpdateWidget(oldWidget):当父 Widget 重建并传递新的 Widget 配置时,会调用这个方法。旧 Widget 会被作为参数传入。可以在此处比较新旧 Widget,并决定是否需要重新初始化一些状态。
  7. setState():这是一个通知框架状态已变化的方法,调用后会重新构建 Widget。它本身不是生命周期方法,但会触发 build。
  8. deactivate():当 State 对象从树中移除时调用,可能会被重新插入到树的另一个位置(比如使用 GlobalKey 时)。
  9. dispose():当 State 对象从树中永久移除时调用,用于释放资源,如取消计时器、停止动画、清理控制器等。调用后 mounted 属性变为 false。
  10. reassemble():仅在调试模式下调用,用于热重载。在 release 模式下不会调用。

3. 什么是 Flutter tree shaking

Tree Shaking 是一种优化技术,用于减少最终应用的体积。具体来说,它的作用是:

    1. 去除未使用的代码:在构建应用时,Tree Shaking 会分析代码中的依赖关系,并自动移除那些在应用中未被引用或使用的代码。这包括未使用的库、类、函数等。
    1. 提高性能:通过减小应用的体积,Tree Shaking帮助提高应用的加载速度和运行性能,因为较少的代码意味着更少的资源消耗。
    1. 编译时优化:Flutter 在编译过程中会进行 Tree Shaking,确保在最终的构建产物中只包含必要的代码。

4. Spacer 小部件是什么?

  • 需要在组件之间添加弹性空白,或者将组件推到主轴起点、中间或末尾(如居右、均匀分隔),优先考虑 Spacer。
  • 需要让某个子组件填满剩余空间,或者多个子组件按特定比例分配剩余空间,应使用 Expanded。

总结:Spacer 用于“创造空白”,Expanded 用于“扩展内容”。

5. hot restart 和 hot reload 之间的区别是什么?

定义:

  • hot restart:是一种重启应用的方式,它会重新加载整个应用及其状态。会清除当前状态,并重新启动应用,因此所有的状态、数据和输入都会丢失。

  • hot reload:是一种快速更新代码的方式,它可以在不重启应用的情况下,立即反映对代码的更改。会保留应用的当前状态,包括用户输入、动画等。这样可以在不丢失进度的情况下查看更改,主要用于更新 UI 方面的代码,如 Widget 的布局或样式。

6. InheritedWidget 是什么?(因海瑞提的·维基特)

  1. 用于在 Widget 树中向下传递数据。它允许子 Widget 访问其祖先 Widget 中提供的数据,从而实现状态管理和数据共享。
  2. InheritedWidget 的工作原理是:当在 Widget 树中插入一个 InheritedWidget 时,其子组件可以通过 context.dependOnInheritedWidgetOfExactType() 来注册依赖关系。当 InheritedWidget 的数据发生变化并重建时,所有依赖它的子组件都会重新构建。

实际应用场景
主题数据:Flutter 内置的 Theme 就是一个 InheritedWidget
用户信息:在应用多个地方共享用户数据
配置信息:应用配置、语言设置等
状态管理:作为更复杂状态管理方案(如 Provider)的基础

注意事项
性能考虑:只在需要时使用,避免过度使用导致不必要的重建
数据类型:适合共享不变或较少变化的数据
测试:使用 InheritedWidget 的组件更容易测试,因为它们不直接依赖于具体实现。

7. 为什么构建(build)方法在 State 上而不是在 StatefulWidget 上?

构建方法放在 State 类中是为了更好地管理和反映状态变化,使得 StatefulWidget 能够动态响应用户交互和其他条件的变化。这种设计使得 Flutter 的状态管理更加高效和灵活。

从设计逻辑看
State 类不仅负责构建 UI,还包含了管理状态的逻辑。将构建方法放在 State 中,可以更清晰地分离出 Widget 的外观(StatefulWidget)和其行为(State),将构建方法放在 State 中,能够确保 UI 始终反映最新的状态变化

从生命周期看
在 StatefulWidget 中,状态信息可能会发生变化,这些变化需要在构建方法中反映出来。通过将构建方法放在 State 类中,Flutter 能够在状态变化时仅重建相关的部分,提高性能。

8. pubspec 文件在 Flutter 中是什么?

主要用于管理项目的依赖项、元数据和其他设置。以下是该文件的主要功能和构成:

1.可以列出项目所需的外部库(packages),这些库可以通过 Dart 的包管理器 pub 来自动下载和管理

2.项目名称和版本:可以在文件中定义项目的名称、版本、描述等信息。
3.环境配置:可以指定使用的 Flutter SDK 的版本。

9. Flutter 是如何实现原生性能和体验的?

1.渲染引擎
Skia:Flutter 使用 Skia 作为其渲染引擎。Skia 是一个高性能的 2D 图形库,可以直接与底层操作系统的图形 API 进行交互(如 OpenGL 和 Vulkan),从而实现高效的图形渲染。

2.直接访问原生 API
Platform Channels:Flutter 通过平台通道(Platform Channels)与原生代码进行通信。开发者可以在 Flutter 中调用原生 Android 或 iOS 的 API,实现对硬件功能(如相机、GPS 等)的访问。

3.Widget 树
自绘 Widget:Flutter 的 UI 是完全由 Widgets 构成的,Flutter 不依赖于原生 UI 组件,而是通过绘制其自己的组件来实现。从而确保了在不同平台上具有一致的外观和行为。

4.高效的性能
AOT 编译:Flutter 使用 Ahead-of-Time (AOT) 编译,将 Dart 代码编译为原生机器码,从而提高应用的启动速度和运行性能。

5.热重载
开发体验:Flutter 提供热重载功能,使得开发者在进行 UI 修改时可以立即查看效果,而无需重新启动应用,这大大提高了开发效率。

Flutter 渲染原理:

在Flutter渲染的流程中,有三棵树,Flutter引擎渲染是针对Render树中的对象进行渲染。

1.Widget 树 所有Widget都会 调用 creatElement 方法 创建 Element 对象,将Element对象加入Element树中,后面都会调用 mount方法

但是Element分三种:
a.RanderElement 继承 RanderObjectElement ,主要是创建RenderObject,通过mount方法创建RenderObject。

b.StatefulElement 继承 ComponentElement,调用createState方法,创建State,然后将Widget赋值给State对象,最后调用state的buidl方法并且将自己(Element) 传出去

c.StatelessElement 继承 ComponentElement,主要调用build方法,并将自己回调出去。

2.Element 树 :所有继承 Widget的树 都有 Element树,他们属于 1对1 关系。在 Element树中都调用
mount 方法, 然后 mount 里面 不是继承 RenderObjectWidget 就结束,然后是的话,则调用CreatRenderObject 创建RenderObject 。

StatelessWidget的Element
1.StatelessWidget 会创建 Element

  1. 然后Element创建就会调用 mount方法
    3.mount里面会调用 Widget 的build方法进行渲染,并且将自己Element 传递出去。

StatafulWidget

state和 Widget共用一个 element

3.Render 树 (渲染引擎去渲染的树)(只有继承 RenderObjectWidget的才会创建 RenderObject树,才会被渲染引擎渲染 )

10.Key的原理

1.Keys 是一个用于标识 Widget 的对象,帮助 Flutter 识别和管理 Widget 的状态。

1.GlobalKey:
GlobalKey是一个全局唯一的键,一种特殊的 Key。用于跨 Widget 树访问状态和方法。GlobalKey 允许你在不同的 Widget 之间共享状态,特别是在使用 StatefulWidget 时。它的主要用途是确保在 Widget 树重建时仍能保留和访问 Widget 的状态。当 Widget 被重建时,GlobalKey 保持对其状态的引用,因此可以在重建过程中保持状态。
示例:
1.在处理表单时,你可以使用 GlobalKey 来访问和验证表单的状态。
2.使用 GlobalKey 可以直接控制 Widget 的状态方法,比如在动画中调用
3.当你的 Widget 树结构复杂,且多个子 Widget 可能会被重建时,GlobalKey 可以帮助你保持子 Widget 的状态。

注意

谨慎使用:GlobalKey 会破坏 Widget 的封装性,应仅在必要时使用
性能考虑:频繁使用可能影响性能
生命周期:确保在 Widget 被销毁后不再访问其 Key

2.ValueKey:
根据给定的值来识别 Widget,通常用于列表中的元素。
示例:在列表中修改顺序时,确保正确更新每个元素的状态。
3.ObjectKey:
通过对象的引用来识别 Widget,适用于需要比较对象的情况。
4.UniqueKey:
每次创建时都会生成一个唯一的 Key,适合临时 Widget。

11.PageRoute

1.PageRoute 是一个用于管理应用中页面导航的抽象类
2.PageRoute 负责在不同页面(或屏幕)之间进行导航。它管理了页面的堆栈,使得用户可以前往新页面或返回到之前的页面。
3.有两种效果
MaterialPageRoute:用于 Material Design 风格的应用,提供从底部向上推入页面的动画。
CupertinoPageRoute:用于 iOS 风格的应用,提供从右向左推入页面的动画。
4.PageRoute 提供了一些生命周期方法,如 didChangeDependencies 和 dispose,用于在页面进入和退出时执行特定操作。

12.解释 async , await 和 Future

1.async、await 和 Future 是处理异步编程的关键概念。它们可以帮助你编写非阻塞的代码,使得应用能够在执行长时间运行的任务时保持响应。

2.Future 是一个表示可能在未来某个时间点完成的异步操作的对象。它可以用于表示一个延迟的值,通常用于处理异步任务的结果。
状态:
未完成(Pending):Future 仍在进行中。
已完成(Completed):Future 执行完毕,可以获取结果。
已失败(Error):Future 执行过程中出现错误。

3.async 是一个修饰符,用于声明一个异步函数。使用 async 修饰的函数会返回一个 Future,即使函数内部没有显式地返回 Future。在 async 函数中,你可以使用 await 关键字等待一个 Future 完成。
4.await 是一个关键字,用于在 async 函数中等待一个 Future 完成,
使用 await 会暂停 async 函数的执行,直到 Future 完成,并返回结果,让异步代码看起来像同步代码,从而提高代码的可读性。只能在 async 函数中使用。

总结:

Future:表示一个异步操作的结果,可以是未完成、已完成或已失败。
async:用于声明异步函数,返回一个 Future。
await:在 async 函数中等待一个 Future 完成,并获取其结果。

13.你如何动态更新列表视图?

1.利用 StatefulWidget 和 setState() 方法,可以在更新数据时重新构建列表。
2.使用 Provider 或其他状态管理。
3.使用 StreamBuilder
如果数据来自异步源(如网络请求或数据库),可以使用 StreamBuilder 来动态更新列表。

14.stream 是什么??

1.Stream 是一种用于处理异步数据流的机制。它允许你接收一系列异步事件,而不仅仅是单个值。Streams 非常适合处理动态数据源,例如用户输入、网络请求、文件读取等。
2.Stream 允许你以异步的方式接收数据,不会阻塞当前线程。这使得应用在处理数据时仍然能够保持响应。

Stream 的类型
单订阅 Stream:
只能有一个订阅者,适合处理一次性事件流,例如从文件读取数据。
广播 Stream:
可以有多个订阅者,适合处理需要广播给多个监听者的事件,例如用户输入或网络请求。

14. Ticker 、 Tween 和 AnimationController 是什么?

Ticker:用于生成时间片,通常与动画相关联。
Tween:定义动画的起始值和结束值,用于在值之间插值。
AnimationController:控制动画的播放,包括启动、停止和反转。它生成一个时间值(通常在 0.0 到 1.0 之间),用于与 Tween 结合使用。

15. ephemeral 状态是什么?

Ephemeral 状态是 Flutter 中一种局部且短期存在的状态,适合用于管理特定 Widget 的状态。它通过 StatefulWidget 管理,适用于用户输入、动画和 UI 状态等场景。与之相对的是 app 状态(应用状态),后者是需要在多个 Widget 之间共享的持久状态。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 初级工程师 1. 核心概念与 Widget 基础 1.1 什么是 Flutter?它的主要优势是什么? 标准答案:...
    巴糖阅读 148评论 0赞 0
  • 一、webf/Kraken 介绍 Kraken Kraken 是一款采用基于 Flutter 而实现的自绘渲染引擎...
    Jason1226阅读 276评论 0赞 0
  • 1、Dart 当中的 「…」表示什么意思? Dart 当中的 「…」意思是 「级联操作符」,为了方便配置而使用。 ...
    leeandfy阅读 91评论 0赞 0
  • 一、flutter与原生通信,三种通道的区别 1.1 MethodChannel Flutter与Native端相...
    耿宏达阅读 1,934评论 0赞 4
  • Dart 相关 1、Dart 当中的 「..」表示什么意思? 级连操作符 “..” 和 “.” 不同:调用..后返...
    af06e7def7a7阅读 2,591评论 0赞 2

友情链接更多精彩内容