| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Flutter深入理解-Flutter面试 -> 正文阅读 |
|
[移动开发]Flutter深入理解-Flutter面试 |
未来可能要准备Flutter的面试机会,所以在网上找了一圈与Flutter相关的面试题,提前准备下。 一、Dart 部分Dart 语言综合了动态语言和静态语言的特性,动态语言指的是可以例如 dynamic 可以在运行用不同的类型数据给变量赋值,var 可以在运行时确定真正的数据类型,而不用在声明的时候就确定了将来要赋值的数据类型。同时,Dart 也是单线程的,跟 JS 类似,通过事件驱动模型来运行整个代码的执行过程。下面提出一些有意思的东西或者概念。 1. Dart 语言类型Dart 属于强类型语言,但是可以用 var 来声明变量,Dart 会自动推到出数据类型,var 实际上是编译期的“语法躺”。dynamic 表示动态类型,被编译后,实际上是一个 object 类型的,在编译期间不进行任何的类型检查,而是在运行期间进行类型检查。 2. Dart 中数组Dart 中 数组和 List 是一样的。 3. Dart 支持闭包。4. Dart num 类型Dart 中 number【num 类型】分为 int 和 double, 没有 float 类型。 5. Dart 级连操作符Dart 中级连操作符可以方便配置逻辑,如下代码:
6. Dart 赋值操作符赋值操作符,比较有意思的赋值操作符:
7. 函数可选方法参数Dart 方法可以设置参数默认值和指定名称
8. Dart 作用域Dart 没有关键字 public、private 等修饰,_ 下划线直接代表 private,但是有 @protected 注解。 9. 构造方法Dart 中的多构造方法,可以通过命名方法实现。默认构造方法只能有一个,而通过 Model.empty() 方法可以创建一个空参数的类,其实方法名称随你喜欢,而变量初始化值时,只需要通过 ths.name 在构造方法中指定即可:
10. getter setter 重写Dart 中所有的基础类型、类等都继承 Object,默认值是 NULL,自带 getter 和 setter,而如果是 final 或者 const 的话,那么它只有一个 getter 方法,Oject 都支持 getter、setter 重写:
11. Assert(断言)assert 只在检查模式时有效,在开发过程中,assert(unicorn == null); 只有条件为真的时候才正常,否则直接抛出异常,一般用在开发过程中,某些地方不应该出现什么状态的判断。 12. 重写运算符如下面重载 operator 后对类进行 +/- 操作
支持重载的操作符 13. 类、接口、继承Dart 中没有接口,类都可以作为接口【使用 abstract 关键字】,把某个类当接口使用实现时,只需要使用 implements ,然后重写父类方法即可。Dart 中支持 mixins, 按照出现顺序应该为 extends, mixins, implements。 14. ZoneDart 中可以通过 Zone 表示指定代码执行的环境,类似于一个沙盒概念。在 Flutter 中 C++ 运行Dart 也是在 _runMainZoned 内执行 runZoned 方法启动,而我们也可以通过 Zone,在运行环境内捕获全局异常等信息。
同时你可以给 runZoned 注册方法,在需要时执行回调,如下代码所示,这样的在一个 Zone 内任何地方,只要能够获取 onData 这个 ZoneUnaryCallback, 就都可以调用到 handleData
如上代码可以给我们以启发,如果我们在 App 中如果需要统一处理某件事件,那么就可以这样发送消息给 Zone 的 ZoneUnaryCallback 回调给处理。 异步逻辑可以通过 scheduleMicrotask 可以插入异步执行方法:
思考:但是这种微任务又是干什么用的呢?和普通的事件又有什么区别呢??? 15. FutureFuture 简单来说就是对 Zone 的封装使用。比如 Future.microtask 中主要是执行了 Zone 的 scheduleMicrotask,而 result._complete 最后调用的是 _zone.runUnary 等等。
Dart 中可以通过 async /await 或者 Future 定义异步操作,而事实上 async/await 也只是语法糖,最终还是通过编译器转为 Future 。 16. StreamStream 也是对 Zone 的另外一种封装使用。Dart 中另外一种异步操作,async*/yield 或者 Stream 可定义 Stream 异步,async*/yield 也是一种语法糖,最终还是通过编译器转为 Stream、Stream 还支持同步操作。 一、 Stram 中主要有 Stream、StreamController、StreamSink 和 StreamSubscription 四个关键对象,大致可以总结为: 1. StreamController:如类名描述,用于整个 Stream 过程的控制,提供各类接口用于创建各种事件流。 2. StreamSink:?一般作为事件的接入口,如提供 add,addStream 等。 3. Stream:事件源本身,一般可用于监听事件或者对事件进行转换,如 listen、where。 4. StreamSubscription: 事件订阅后的对象,表面上用于管理订阅过等各种操作,如 cancel、pause, 同时在内部也是事件的中转关键。 二、一般通过 StreamController 创建 Stream;通过 StreamSink?添加事件;通过 Stream 监听事件;通过 StreamSubscription 管理订阅。 三、Stream 中支持各种变化,比如 map、expad、where、take等操作,同时支持转换为Futrue。 17. await for
输出结果:
await for 和 listen 的作用很相似,都是获取流中数据然后输出,但是正如 await for 所示,如果 stream 没有传递完成,就会一直阻塞在这个位置上,上面循环结束了是最后输出的,下面给一个listen 的实例,一看就懂。
输出结果:
?所以 await for 一般都用在直到 stream 什么时候完成,并且必须等待传递完成之后才能使用,不然就会一直阻塞,造成类似 Android ANR 的问题。 二、Flutter部分Flutter 和 React Native 不同主要在于 Flutter UI 是直接通过 skia 渲染的,而React Native 是将 js中的控件转化为原生控件,通过原生去渲染的。 1. Widget 、Element、RenderObject、LayerFlutter 中存在 Widget、Element、RenderObject、Layer 四颗树,其中 Widget 与 Element 是一对多的关系。Widget 只是一种UI描述,并不具备任何的绘制能力。 2. Element 对应关系Element 中持有 Widget 和 RenderObject,而 Element 与 RenderObject 是一对一的关系【除去 Element 不存在 RenderObject 的情况,如 Component 是不具备 RenderObject】 3. isRepaintBoundry当 RenderObject 的 isRepaintBoundry 为 true 时,那么这个区域形成一个Layer, 所以不是每个RenderObject 都具备 Layer 的,因为这受 isRepaintBoundry 的影响。 4. State 状态Flutter 中 Widget 是不可变,每次保持一帧,如果发生改变是通过 State 实现跨帧状态保存,而真实完成布局和绘制数据的 RenderObject, Element 充当两者的桥梁,State 就是保存在 Element中。【跨帧状态保存的意思就是在不同帧变化的时候保留数据】 5. BuildContextFlutter 中的 BuildContext 只是接口,而 Element 实现了它。 6. MarkNeedsBuildFlutter 中 setState 其实是调用了 markNeedsBuild, 该方法内部标记此 Element 为 dirty, 然后在下一帧 WidgetBinding.drawFrame 才会被绘制【需要等待Vsync 信号】,这可以看出 setState 并不是立即生效的。 7. MarkNeedsPaintFlutter 中 RenderObject 在 attach /layout 之后会通过 markNeedsPaint(); 使得页面重绘,流程大概如下: 通过 isRepaintBoundry 往上确定了更新区域,通过 requestVisualUpdate方法触发更新往下绘制。正常情况 RenderObject 的布局相关方法调用顺序是:layout--->performReszie-->performLayout----> markNeedsPaint,但是用户一般不会直接调用 layout,而是通过 markNeedsLayout, 具体流程如下: 8. Flutter Json转Object?Flutter 中一般 json 数据从 String 转为 Oject 的过程都需要先经过 Map 类型。 9. InheritedWidgetFlutter 中 InheritedWidget 一般用于状态共享,如 Theme、Localizations、MediaQuery 等,都是通过它实现共享状态,这样我们就可以通过 context 去获取共享的状态,比如 ThemeData theme = Theme.of(context);
10. 判断更新Flutter 中默认主要通过 runtimeType 和 key判断更新:
11. Flutter 中生命周期?Flutter 中的生命周期 1. initState() 表示当前 State 将和一个 BuildContext 产生关联,但是此时BuildContext 没有完全装载完成,如果你需要在该方法中获取 BuildContext, 可以 new Future.delayed(const Duration(seconds:0, (){})); 一下。更准确说现在应该是用 ScheduleBinding 。 2. didChangeDependencies() didChangeDependencies() 在 initState() 之后调用,当 State 对象的依赖关系发生变化时,该方法被调用,初始化时也会调用。【State对象的依赖关系发生变化时是指的 Widget 发生变化?】 3. deactive() deactive() 当 State 被暂时从视图树中移除时,会调用这个方法,同时页面切换时,也会调用【新版本中已经消失】。 4. dispose() dispose() Widget 销毁了,在调用这个方法之前,总会调用 deactive()。 5. didUpdateWidget() didUpdateWidget 当 Widget 状态发生变化时,会调用。 12. StreamBuilder 和 FutureBuilder通过 StreamBuilder 和 FutureBuilder 我们可以快速使用 Stream 和 Future 快速构建我们的异步控件。 13. WidgetsFlutterBindingFlutter 中 runApp 启动入口其实是一个 WidgetsFlutterBinding,它主要是通过 BindingBase 的子类GestureBinding、ServiceBinding、ScheduleBinding、PaintingBinding、SemanticsBinding、RenderBinding、WidgetsBinding 等,通过 mixins 的组合而成的。 14. Dart 线程Flutter 中的 Dart 的线程是以事件循环和消息队列的形式存在,包含两个任务队列,一个是 microtask 内部队列,一个是 event 外部队列,而 microtask 的优先级又高于 event 。
思考:那么哪些算是 microtask ,哪些是 event 呢? 15. Flutter 四大线程Flutter 中存在四大线程,分别是 UI Runner、GPU Runner、IO Runner 、Platform Runnber (原生主线程),同时在Flutter 中可以通过 isolate 或者 compute 执行真正的跨线程异步操作。 16. PlatformViewFlutter 中可以通过 PlatformView 可以嵌套原生 View 到 Flutter UI 中,这里面其实是使用了Presentation + VirtualDisplay + Surface 等实现的,大致原理就是: 使用了类似副屏显示的技术,VirtualDisplay 类代表一个虚拟显示器,调用 DisplayManager 的createVirtualDisplay() 方法,将虚拟显示器的内容渲染在一个 Surface 控件上,然后将 Surface 的id 通知给 Dart , 让 engine 绘制时,在内存中找到对应的 Surface 画面内存数据,然后绘制出来。实时控件截图渲染显示技术。 17. Flutter JIT 模式和 AOT 模式Flutter 的 Debug 下是 JIT 模式,release 下是AOT模式。【JIT是每次运行的时候编译成机器码,AOT是在安装的时候就编译成机器码】 18. AutomaticKeepAliveClientMixinFlutter 中可以通过 mixins AutomaticKeepAliveClientMixin,然后重写 wantKeepAlive 保持住页面,记得在被保持的页面 build 中调用 super.build 。(因为 mixins 特性) 19.? Flutter 手势事件Flutter 手势事件主要是通过竞技判断的: 主要有 hitTest 把所有需要处理的控件对应的 RenderObject,从 child 到 parent 全部组合成列表,从最里面一直添加到最外层。然后从队列头到 child 开始 for 循环执行 handleEvent 方法,执行 handleEvent 的过程不会被拦截打断。 一般情况下 Down 事件不会决出胜利者,大部分时候是在 MOVE 或者 UP 的时候才会决出胜利者。竞技场关闭时只有一个的就直接胜出响应,没有胜利者就拿排在队列第一个强制胜利响应。 同时还有 didExceedDeadline 处理按住时的 Down 事件额外处理,同时手势处理一般在 GestureRecognizer 的子类进行。 20. ViewPort?Flutter 中 ListView 滑动其实都是通过 ViewPort 中的 child 布局来实现显示的。 21. 状态管理常见状态管理的:目前有 scope_model、flutter_redux、fish_redux、bloc+Stream 等几种模式。 21. Platform Channel?Flutter 中可以通过 Platform Channel 让 Dart 代码和原生代码通信的: 1. BasicMessageChannel: 用于传递字符串和半结构化的信息。 2. MethodChannel : 用于传递方法调用(method invocation) 3. EventChannel: 用于数据流(event streams)的通信。 同时 Platform Channel 并非是线程安全的,更多详细可查阅咸鱼技术的? 其中基础数据类型映射如下: 22. Android 启动页Android 中 Flutter 默认启动时会在 FlutterActivityDelegate.java 中读取 AndroidManifest.xml 内meta-data 标签,其中 io.flutter.app.android.SplashScreenUntilFirstFrame 标志位如果为 true,就会启动 Splash 画面效果(类似iOS 的启动页面)。 启动时原生代码会读取 android.R.attr.windowBackground 得到指定的 Drawable,用于显示启动闪屏效果,之后并且通过 flutterView.addFirstFrameListener,在 onFirstFrame 中移除闪屏。 参考:? |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 11:54:28- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |