Flutter是谷歌推出的开源移动应用开发框架,只要一套代码就可以构建测试和发布,适用于移动Web桌面嵌入式平台应用,是一个跨端的平台开发框架。
原生的开发优势:速度快 用户体验好;缺点:开发成本高,不同平台上需要维护不同的代码,动态化(有新功能的话 就要发版)
移动端跨平台技术演进:
Flutter优势:
跨平台
一份代码多端运行,兼顾Android、iOS、Web、Windows、MacOS、Linux六个平台
高性能
release模式下AOT编译Skia高性能自绘引擎,接近原生体验
高效
热重载、快速构建开发效率高
开源协作
google支持,开源、透明、可靠
Dart语言
语法简洁,容易上手
1.Flutter基础
1.1 整体架构
Flutter架构模式如下:
1.2 线程模型
Flutter engine不会自己创建和管理线程,线程的创建和管理全部都由嵌入层负责。
Platform Task Runner
运行在平台上的主线程.主要功能是处理和Engine层的交互,处理平台层的消息。
UI Task Runner
执行Dart root isolate。主要功能是渲染与处理Vsync信号,将Widget转换成Layer Tree
GPU Task Runner
执行设备的GPU命令
IO Task Runner
文件读取和资源加载
每一个engine启动的时候,会为UI GPU IO Runner各自创建一个新的线程,但是所有的Engine实例共享同一个Platform Runner和线程
2.Widget
Flutter的理念是”万物皆Widget“,核心思想是用widget来构建UI界面。
widget相当于一个配置文件,当widget的状态发生改变时,会重新构建UI。Flutter框架会对比前后变化的不同,重新渲染更新界面显示。
2.1 生命周期
Flutter生命周期主要指的是StatefullWidget的生命周期
createState是StatefulWidget中创建的State的方法,当StatefulWidget被调用时会立即执行createState
initState是初始化state的调用,与服务端进行交互,请求服务端的数据来设置state
didChangeDependencies是state对象的依赖发生变化时进行调用
build用来返回需要渲染的widget,build会被调用多次,在这个函数里只能返回widget的相关逻辑,避免因为多次执行导致状态异常
reassemble是在debug模式下,每次热重载调用的函数
在widget重新构建时,Flutter framework会调用Widget.canUpdate来检测widget树中同一位置的新旧节点,然后决定是否需要更新。如果Widget.canUpdate返回true的话,就会调用回调方法didUpdateWidget。父组件发生build的情况下,子组件的didUpdateWidget方法才会被调用,调用之后一定会调用build方法
deactivate是在组件被移除节点后调用
如果组件被移除节点,并且没有被插入到其他节点时,则会调用dispose ,永久删除组件并且释放它的组件资源
总结:生命周期的4个阶段。
初始化阶段:createState和initSate
组件创建阶段:didChangeDependencies和build
触发组件build:
didChangeDependencies、setState或者didUpdateWidget都会引发组件重新build销毁阶段:deactivate和dispose
2.2 常用Widget
常用的Widget如下:
3.Navigator
用来实现Flutter中的页面跳转,即路由管理
Flutter的路由管理与原生开发类似,栈存储,都是进栈和出栈。
Navigator.push()进栈,打开一个新页面
Navigator.pop()出栈,关闭页面,并且返回数据给到主屏界面。pop的第二个参数是可选的,如果传递了这个参数,数据会通过future的方法传递返回值
4.网络请求和序列化数据
练习请求接口(https://sanlittt.github.io/lianxisheng.github.io/test.json)
5.通信
Flutter的本质是一个UI框架,运行在宿主平台上,Flutter本身是无法提供一些系统能力的,比如蓝牙、相机、GPS等等。因此Flutter如果要调用这些能力,就必须和原生平台进行通信。
Platform Channel是一个异步的消息通道,消息在发送前被处理成二进制消息,接收到的二进制消息会解码成Dart的值。它传递的消息类型只能是对应的解码器支持的值,所有的解码器都支持空消息。
Flutter中有3种Platform Channel
- BasicMessageChannel:用来传递数据
- MethodChannel:用来传递方法
- EventChannel:用来传递事件
6.渲染原理
Flutter渲染包含3棵树:Widget、Element、RenderObject
Widget
是存放渲染内容,只是一个配置的数据结构,非常轻量,在页面刷新的过程中随时会重建
Element
同时持有Widget和RenderObject,存放上下文信息,通过它来遍历视图树 支撑UI结构
RenderObject
根据Widget的 布局属性进行layout,paint。负责真正的渲染
从创建到渲染的大致流程:根据widget生成element,创建相应的RenderObject并关联到Element.renderObject属性上,最后通过RenderObject来完成布局排列和绘制。
当需要更新UI时,framework通知engine,engine会等到下一个Vsync信号到达时,通知framework进行animate build layout和paint,最后生成layer提交给engine。engine会把layer进行组合,生成纹理,最后通过open GL接口提交数据给GPU,GPU经处理后在显示器上面显示。
页面刷新的具体操作流程如下:
常见的优化策略:
减少build中的逻辑处理
因为widget在页面刷新的过程中,会通过build重建,应该只在build中处理跟UI相关的逻辑
提高build效率
setState尽量下发到底层的节点
提高paint效率
通过RepaintBoundry创建单独的layer减少重绘区域
减少ClipPath、saveLayer使用
saveLayer会在GPU中分配一块新的绘图缓冲区,切换绘图目标,此操作非常耗时
ClipPath会影响每个绘图指令,做一些相交操作,相交之外的部分会被剔除掉,也是非常耗时的
减少Opacity使用
尤其在动画中,会导致widget的每一帧都被重建。可以使用AnimatedOpacity或FadeInImage进行代替。