跨端Flutter学习

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进行代替。