前言
近期有不少人咨询了我 Flutter 相关的问题,其中有不少是和面试相关的,如今一些招聘上也开始罗列 Flutter 相关要求,于是想了想还是写一期总结吧,也算是 Flutter 学习的复习。
系统完整的学习是必须需要的,这里只能帮你总结一些知识点,更多的还请查阅 Flutter 官网。喜欢的小伙伴欢迎关注,我会定期分享Android知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿。
Flutter 部分
基础知识
Flutter 和 React Native 不同主要在于 Flutter UI是直接通过 skia 渲染的 ,而 React Native 是将 js 中的控件转化为原生控件,通过原生去渲染的 。
Flutter 中存在
Widget
、Element
、RenderObject
、Layer
四棵树,其中Widget
与Element
是一对多的关系Element
中持有Widget
和RenderObject
, 而Element
与RenderObject
是一一对应的关系当
RenderObject
的isRepaintBoundary
为true
时,那么个区域形成一个Layer
,所以不是每个RenderObject
都具有Layer
的,因为这受isRepaintBoundary
的影响。Flutter 中
Widget
不可变,每次保持在一帧,如果发生改变是通过State
实现跨帧状态保存,而真实完成布局和绘制数组的是RenderObject
,Element
充当两者的桥梁,State
就是保存在Element
中。Flutter 中的
BuildContext
只是接口,而Element
实现了它。Flutter 中
setState
其实是调用了markNeedsBuild
,该方法内部标记此Element
为Dirty
,然后在下一帧WidgetsBinding.drawFrame
才会被绘制,这可以看出setState
并不是立即生效的。Flutter 中
RenderObject
在attch
/layout
之后会通过markNeedsPaint();
使得页面重绘,流程大概如下:
通过isRepaintBoundary 往上确定了更新区域,通过 requestVisualUpdate 方法触发更新往下绘制。
正常情况
RenderObject
的布局相关方法调用顺序是 :layout
->performResize
->performlayout
->markNeedsPaint
, 但是用户一般不会直接调用layout
,而是通过markNeedsLayout
,具体流程如下:
Flutter 中一般 json 数据从
String
转为Object
的过程中都需要先经过Map
类型。Flutter 中
InheritedWidget
一般用于状态共享,如Theme
、Localizations
、MediaQuery
等,都是通过它实现共享状态,这样我们可以通过context
去获取共享的状态,比如ThemeData theme = Theme.of(context);
在
Element
的inheritFromWidgetofExactType
方法实现里,有一个Map<Type, InheritedElement> _inheritedWidgets
的对象。
_inheritedWidgets
一般情况下是空的,只有当父控件是InheritedWidget
或者本身是InheritedWidgets
时才会有被初始化,而当父控件是InheritedWidget
时,这个Map
会被一级一级往下传递与合并 。所以当我们通过
context
调用inheritFromWidgetofExactType
时,就可以往上查找到父控件的Widget
。
static bool canUpdate(Widget oldWidget, Widget newWidget) { return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key; } }
Flutter 中的生命周期
initState()
表示当前State
将和一个BuildContext
产生关联,但是此时BuildContext
没有完全装载完成,如果你需要在该方法中获取BuildContext
,可以new Future.delayed(const Duration(seconds: 0, (){//context});
一下。didChangeDependencies()
在initState()
之后调用,当State
对象的依赖关系发生变化时,该方法被调用,初始化时也会调用。didUpdateWidge
当widget
状态发生变化时,会调用。
通过
StreamBuilder
和FutureBuilder
我们可以快速使用Stream
和Future
快速构建我们的异步控件。Flutter 中
runApp
启动入口其实是一个WidgetsFlutterBinding
,它主要是通过BindingBase
的子类GestureBinding
、ServicesBinding
、SchedulerBinding
、PaintingBinding
、SemanticsBinding
、RendererBinding
、WidgetsBinding
等,通过mixins
的组合而成的。Flutter 中的 Dart 的线程是以事件循环和消息队列的形式存在,包含两个任务队列,一个是 microtask 内部队列,一个是 event 外部队列,而 microtask 的优先级又高于 event 。
因为 microtask 的优先级又高于 event, 同时会阻塞event 队列,所以如果 microtask 太多就可能会对触摸、绘制等外部事件造成阻塞卡顿哦。
Flutter 中存在四大线程,分别为
UI Runner
、GPU Runner
、IO Runner
,Platform Runner
(原生主线程) ,同时在 Flutter 中可以通过isolate
或者compute
执行真正的跨线程异步操作。
PlatformView
Flutter 中通过 PlatformView
可以嵌套原生 View
到 Flutter
UI 中,这里面其实是使用了 Presentation
+ Virtualdisplay
+ Surface
等实现的,大致原理就是:
使用了类似副屏显示的技术,Virtualdisplay
类代表一个虚拟显示器,调用 displayManager
的 createVirtualdisplay()
方法,将虚拟显示器的内容渲染在一个 Surface
控件上,然后将 Surface
的 id 通知给 Dart,让 engine 绘制时,在内存中找到对应的 Surface
画面内存数据,然后绘制出来。em... 实时控件截图渲染显示技术。
Flutter 的 Debug 下是 JIT 模式,release下是AOT模式。
Flutter 中可以通过
mixins AutomaticKeepAliveClientMixin
,然后重写wantKeepAlive
保持住页面,记得在被保持住的页面build
中调用super.build
。(因为 mixins 特性)。Flutter 手势事件主要是通过竞技判断的:
主要有 hitTest
把所有需要处理的控件对应的 RenderObject
, 从 child
到 parent
全部组合成列表,从最里面一直添加到最外层。
然后从队列头的 child 开始 for 循环执行 handleEvent
方法,执行 handleEvent
的过程不会被拦截打断。
一般情况下 Down 事件不会决出胜利者,大部分时候是在 MOVE 或者 UP 的时候才会决出胜利者。
竞技场关闭时只有一个的就直接胜出响应,没有胜利者就拿排在队列第一个强制胜利响应。
同时还有 didExceedDeadline
处理按住时的 Down 事件额外处理,同时手势处理一般在 GestureRecognizer
的子类进行。
Platform Channel
Flutter 中可以通过 Platform Channel
让 Dart 代码和原生代码通信的:
同时 Platform Channel
并非是线程安全的 。
其中基础数据类型映射如下:
Android 启动页
Android 中 Flutter
默认启动时会在 FlutterActivityDelegate.java
中读取 AndroidManifset.xml 内 Meta-data
标签,其中 io.Flutter.app.android.SplashScreenUntilFirstFrame
标志位如果为 ture ,就会启动 Splash 画面效果(类似IOS的启动页面)。
启动时原生代码会读取 android.R.attr.windowBackground
得到指定的 Drawable
, 用于显示启动闪屏效果,之后并且通过 FlutterView.addFirstFrameListener
,在onFirstFrame
中移除闪屏。
觉得文章不错的小伙伴帮忙点点赞加关注哦 ,有什么问题的话也欢迎大家前来探讨交流。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。