Flutter 面试知识点:Flutter部分

2019-05-1421:20:52APP与小程序开发Comments3,014 views字数 4087阅读模式

Flutter 和 React Native 不同主要在于 Flutter UI是直接通过 skia 渲染的 ,而 React Native 是将 js 中的控件转化为原生控件,通过原生去渲染的 ,相关更多可查看:《移动端跨平台开发的深度解析》文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

  • Flutter 中存在 WidgetElementRenderObjectLayer 四棵树,其中 WidgetElement 是多对一的关系
  • Element 中持有WidgetRenderObject , 而 ElementRenderObject 是一一对应的关系
  • RenderObjectisRepaintBoundarytrue 时,那么个区域形成一个 Layer,所以不是每个 RenderObject 都具有 Layer 的,因为这受 isRepaintBoundary 的影响。

更多相关可查阅 《Flutter完整开发实战详解(九、 深入绘制原理)》文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

  • Flutter 中 Widget 不可变,每次保持在一帧,如果发生改变是通过 State 实现跨帧状态保存,而真实完成布局和绘制数组的是 RenderObject Element 充当两者的桥梁, State 就是保存在 Element 中。
  • Flutter 中的 BuildContext 只是接口,而 Element 实现了它。
  • Flutter 中 setState 其实是调用了 markNeedsBuild ,该方法内部标记此ElementDirty ,然后在下一帧 WidgetsBinding.drawFrame 才会被绘制,这可以看出 setState 并不是立即生效的。
  • Flutter 中 RenderObjectattch/layout 之后会通过 markNeedsPaint(); 使得页面重绘,流程大概如下:
Flutter 面试知识点:Flutter部分

通过isRepaintBoundary 往上确定了更新区域,通过 requestVisualUpdate 方法触发更新往下绘制。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

  • 正常情况 RenderObject 的布局相关方法调用顺序是 : layout -> performResize -> performLayout -> markNeedsPaint , 但是用户一般不会直接调用 layout,而是通过 markNeedsLayout ,具体流程如下:
Flutter 面试知识点:Flutter部分
  • Flutter 中一般 json 数据从 String 转为 Object 的过程中都需要先经过 Map 类型。
  • Flutter 中 InheritedWidget 一般用于状态共享,如ThemeLocalizationsMediaQuery 等,都是通过它实现共享状态,这样我们可以通过 context 去获取共享的状态,比如 ThemeData theme = Theme.of(context);

ElementinheritFromWidgetOfExactType 方法实现里,有一个 Map<Type, InheritedElement> _inheritedWidgets 的对象。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

_inheritedWidgets 一般情况下是空的,只有当父控件是 InheritedWidget 或者本身是 InheritedWidgets 时才会有被初始化,而当父控件是 InheritedWidget 时,这个 Map 会被一级一级往下传递与合并 。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

所以当我们通过 context 调用 inheritFromWidgetOfExactType 时,就可以往上查找到父控件的 Widget文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

  • Flutter 中默认主要通过 runtimeTypekey 判断更新:
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 对象的依赖关系发生变化时,该方法被调用,初始化时也会调用。
  • deactivate()State 被暂时从视图树中移除时,会调用这个方法,同时页面切换时,也会调用。
  • dispose() Widget 销毁了,在调用这个方法之前,总会先调用 deactivate()。
  • didUpdateWidgewidget 状态发生变化时,会调用。
Flutter 面试知识点:Flutter部分

  • 通过 StreamBuilderFutureBuilder 我们可以快速使用 StreamFuture 快速构建我们的异步控件: 《Flutter完整开发实战详解(十一、全面深入理解Stream)》
  • Flutter 中 runApp 启动入口其实是一个 WidgetsFlutterBinding ,它主要是通过 BindingBase 的子类 GestureBindingServicesBindingSchedulerBindingPaintingBindingSemanticsBindingRendererBindingWidgetsBinding 等,通过 mixins 的组合而成的。
  • Flutter 中的 Dart 的线程是以事件循环和消息队列的形式存在,包含两个任务队列,一个是 microtask 内部队列,一个是 event 外部队列,而 microtask 的优先级又高于 event 。

因为 microtask 的优先级又高于 event, 同时会阻塞event 队列,所以如果 microtask 太多就可能会对触摸、绘制等外部事件造成阻塞卡顿哦。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

  • Flutter 中存在四大线程,分别为 UI RunnerGPU RunnerIO RunnerPlatform Runner (原生主线程) ,同时在 Flutter 中可以通过 isolate 或者 compute 执行真正的跨线程异步操作。

PlatformView

Flutter 中通过 PlatformView 可以嵌套原生 ViewFlutter UI 中,这里面其实是使用了 Presentation + VirtualDisplay + Surface 等实现的,大致原理就是:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

使用了类似副屏显示的技术,VirtualDisplay 类代表一个虚拟显示器,调用 DisplayManagercreateVirtualDisplay() 方法,将虚拟显示器的内容渲染在一个 Surface 控件上,然后将 Surface 的 id 通知给 Dart,让 engine 绘制时,在内存中找到对应的 Surface 画面内存数据,然后绘制出来。em... 实时控件截图渲染显示技术。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html


  • Flutter 的 Debug 下是 JIT 模式,release下是AOT模式。
  • Flutter 中可以通过 mixins AutomaticKeepAliveClientMixin ,然后重写 wantKeepAlive 保持住页面,记得在被保持住的页面 build 中调用 super.build 。(因为 mixins 特性)。
  • Flutter 手势事件主要是通过竞技判断的:

主要有 hitTest 把所有需要处理的控件对应的 RenderObject , 从 childparent 全部组合成列表,从最里面一直添加到最外层。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

然后从队列头的 child 开始 for 循环执行 handleEvent 方法,执行 handleEvent 的过程不会被拦截打断。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

一般情况下 Down 事件不会决出胜利者,大部分时候是在 MOVE 或者 UP 的时候才会决出胜利者。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

竞技场关闭时只有一个的就直接胜出响应,没有胜利者就拿排在队列第一个强制胜利响应。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

同时还有 didExceedDeadline 处理按住时的 Down 事件额外处理,同时手势处理一般在 GestureRecognizer 的子类进行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

更多详细请查看:《Flutter完整开发实战详解(十三、全面深入触摸和滑动原理)》文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

Platform Channel

Flutter 中可以通过 Platform Channel 让 Dart 代码和原生代码通信的:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

  • BasicMessageChannel :用于传递字符串和半结构化的信息。
  • MethodChannel :用于传递方法调用(method invocation)。
  • EventChanne l: 用于数据流(event streams)的通信。

同时 Platform Channel 并非是线程安全的 ,更多详细可查阅闲鱼技术的 《深入理解Flutter Platform Channel》文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

其中基础数据类型映射如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

Flutter 面试知识点:Flutter部分

Android 启动页

Android 中 Flutter 默认启动时会在 FlutterActivityDelegate.java 中读取 AndroidManifset.xml 内 meta-data 标签,其中 io.flutter.app.android.SplashScreenUntilFirstFrame 标志位如果为 ture ,就会启动 Splash 画面效果(类似IOS的启动页面)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

启动时原生代码会读取 android.R.attr.windowBackground 得到指定的 Drawable , 用于显示启动闪屏效果,之后并且通过 flutterView.addFirstFrameListener,在onFirstFrame 中移除闪屏。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

作者:恋猫de小郭
链接:https://juejin.im/post/5cd9875ae51d453d022cb662
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html

文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/12418.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/xcx/12418.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定