聊 · Flutter

曾经的团队是国内最早投入Flutter框架怀抱的团队,后来又有机会负责起了Flutter相关项目,翻回以前写的文章,感慨良多,这是其中的一篇关于这些内容的闲聊。

| 导语Flutter相关的技术资源官网和网友都有过系统且细致的整理,因此这篇文章不是系统的介绍Flutter,而是把我的学习Flutter的一些感受记录分享,内容组织比较零散,想到哪说到哪,欢迎留言讨论。

前言

Dart是Flutter的编程语言,Flutter是Google的UI工具包,用于从单个代码库构建漂亮的本机编译的移动,Web和桌面应用程序。

接下来我们从Dart到Flutter,再到Flutter engine,聊一下我印象深刻的点。

聊·Dart语言:

并发

我一直在项目中反对组员直接使用_beginthread的多线程并发,因为很多人不考虑函数的可重入性,导致埋下许多坑,在我看来多线程弊大于利,于是严格要求大家只能用PostToXxThread的方式使用多线程。而我发现Dart对多线程并发的设计正是我所需要的,彻底解决了多线程加锁互斥的难题,相当于强制使用Post方式,即满足了并发的要求也解决了多线程最让人头疼的线程同步,真是填补了个大坑,Dart干得漂亮

单线程如何解决IO等耗时操作导致的无响应呢?推荐的做法是async-await方式,总体上Dart的async-await设计和JavaScript以及C#的设计大同小异,使用体验好。async-await的方式到了底层其实就是多线程(也不排除协程),但是如果想要像dart的这种async-await编写体验则必须让语言支持垃圾回收,因为在不支持垃圾回收的语言(如C++)是无法处理后await返回后栈对象或者this被释放的场景,因此类似C++语言目前只有“鸡肋版的async-await”。Dart runtime的线程模型基本和chromium高度一致。

空安全

我们通过C++实现了win/mac的跨平台,但是代码里大量的空指针保护代码让我很难受,有时有人忘写了指针判断导致崩溃也会让人很头疼,而Dart也很好的解决了这个问题:

这篇文章对Dart的空安全讨论非常深入:深入理解空安全 | Dart

在其中看到这段话也非常认同:“代码的健全性极大程度地决定了开发者对于自己的代码是否有自信。一艘 大部分时间 都在飘忽不定的小船,是不足以让你鼓起勇气,驶往公海进行冒险的”。

避空运算符是个非常好用的语法糖,但是也会导致很多逻辑缺失异常处理,降低代码鲁棒性,为此我们建议在项目中避免使用逼空运算符:

Dart不支持反射:

如果需要用到反射能力,可以使用代码生成思路实现,基于此思路也提供了相关的dart package: dart的反射

关于反射,有的语言默认全部方法支持反射,有的语言使用语法糖支持显式反射,而dart用代码生成方式支持反射(或者说不支持反射),确实比较出乎我的意料之外的。这说明2点,第一:dart重视性能和编译优化,第二:代码生成这种方式在dart体系中应多处出现。代码生成确实给了语言很大的扩展空间,dart编译器和运行时抛掉了反射,也可以更加专注于代码生成的优化和执行效率,也意味着坚实的走在类似C++极致性能的道路上(我也感觉是chrome里优化V8性能那波人被JavaScript的动态化折磨得不要不要的,为此在dart果断的砍掉了动态化的特性)。

 和其他语言交互:

因为要实现逻辑跨平台,我对Dart语言和其他语言的交互比较关注。Dart毕竟是一种全新的语言,无论设计理念多么先进都会苦于没有丰富的库,因此Dart也更注重和其他语言的通信。

Dart和C语言的交互比较直接:

Dart和Native (java/OC)交互提供了类型安全机制:

Pigeon是一个代码生成器工具,使Flutter和主机平台之间的通信安全,更轻松,更快捷。

果然,代码生成的思路体现在官方的不少库中。这也许也是从chromium里学到的经验吧,chromium里有大量通过脚本生成的代码。

聊·Flutter :

声明式UI

Flutter框架使用的编程范式 (flutter.dev)

Flutter倾向于采取了最新的技术方案,其中UI界面的核心设计模式参考了React对UI开发的探索模型,这一点在Flutter wiki上有多处进行谈论:


对于习惯了传统的UI模型思维方式来说,这种UI开发模式确实需要一段时间的熟悉。不过这种声明式编程方式确实是一种进步的探索,我想从多个方面对此设计进行思考:

  1. 声明式用户界面对渲染引擎层不友好,需要引擎对其做更多的优化(比如渲染引擎要自己计算哪个widget需要重新绘制),当渲染引擎的理论和实践发展到一定程度后,才会出现声明式用户界面框架。声明式用户界面的引擎也必将选择单独的渲染树的实现方式。
  2. 声明式用户界面一定程度上简化了UI开发的复杂度,不需要引入额外的静态语言描述界面结构(如web的html,qt的.ui文件),让界面的实现集中一处。是个重要的进步。我认为相关的代码逻辑能集中一处,就可以大大提高可读性(思考一个大需求的实现,改动了100行代码在10个函数好,还是改动了100个函数每个函数改了10行好)。
  3. 声明式用户界面的开发模式也避免了界面描述文件那种到处插入widget导致bug不易定位的问题。随处可以插入widget的开发方式自然是灵活的,但是灵活换来的代价是代码设计质量无下限,目前来看,编程的主流的方向是限制灵活性,走向约束和规范。
  4. 由于不需要解析界面描述文件,声明式用户界面首帧速度更优。客户端和web都能做UI界面,客户端比web最核心的2个优势就是首帧画面速度和内存占用。如果这两个优势没有了,那客户端同学就可以退出GUI层的开发任务了,专注于Console层了。
  5. 对于界面状态逻辑特别复杂的界面,声明式用户界面的编写规则更容易直观体现出界面和状态之间的关系,即 UI = f (state) 中的f是单独表达的。声明式用户界面的思维模型让界面里的状态和UI表达更为直观。
  6. 对于界面状态不在同一个widget的场景,或者界面状态离widget距离较远时,声明式用户界面反而比较麻烦。在实际的开发中,界面状态的数据大部分是放在比较集中的地方(如根widget),而界面小部件widget则是分散到界面树上,这就导致一个问题,实际开发中flutter的build的界面声明会特别巨大。为此flutter提供了InheritedWidget的特殊widget供孩子共享自己的状态,避免某一个build过于庞大。因此一个复杂界面的主widget都应该从InheritedWidget中派生,避免build函数实现代码的嵌套过于复杂(可以更优雅的使用InheritedWidget:provider | Flutter Package (pub.dev))。但是,InheritedWidget的数据共享是单向的,很多时候确实是不便的,在划分多层次时容易被后续的需求变动推翻,但是单向共享数据的设计是合理的(避免双向依赖)。另一方面,我个人认为有时合理的设计不一定是最佳的设计,如果可能,我会在flutter中实现更方便的state访问机制(引入双向依赖)。
  7. 说到底,声明式用户界面的设计不少完美的,因此我们在使用flutter 声明式编程范式的时候,要知其然更要知其所以然,在实践中灵活发挥其强大的威力,规避弥补其缺陷和不足。

DevTools是个web页面,但是用dart写的!

看上去和web的devtool看起来很像,感觉就是chromium里的devtool的后端,不过其本身是用dart实现的,这也体现出flutter对dart的开发效率的自信,这也让我更加坚定好好学习flutter。

Fluttre的设计原则:

如果对Flutter的设计原则深刻理解后,就会对Flutter很多细节的实现和方向的制定找到一定的内在联系: 

最后再聊一下Flutter Engine。

拉下Flutter engine源码后,粗略看了一下,隐隐的觉得,flutter受chromium项目影响很深,甚至怀疑是同一拨人做出来的。

Build System是GN; 在源码里出现了大量的Copyright 20xx The Chromium Authors的版权声明:

Src目录下的gpu目录就是从chomium里copy出来然后删了不用的文件。

对比了一下flutter和chrome的DEPS文件,核心的库基本是一致的,能找到对应关系:

然后上网上查了一下flutter起源:

Flutter 的诞生其实比较有意思,Flutter 诞生于 Chrome 团队的一场内部实验, 谷歌的前端团队在把前端一些“乱七八糟“的规范去掉后,发现在基准测试里性能居然提高了 20 倍,机缘巧合下 Flutter 就这么被立项。

粗略浏览了一下源码,主要关注lib, runtime, shell三个文件夹即可:

想往flutter里加原生扩展,可以直接在DartIsolate::LoadLibraries添加扩展;想修改VM参数,在DartVM::DartVM构造函数实现。Flutter Engine代码组织清晰,可阅读性很高。让人看一眼就有定制一个的Flutter Engine的冲动。

结语

目前我们的桌面客户端使用C++实现了逻辑跨平台,使用QT实现GUI跨平台。接下来,我们正在计划把APP项目使用Dart实现逻辑跨平台,使用Flutter实现GUI跨平台,最终实现课堂业务的一次开发多平台运行目标。

作为Flutter的初学者,上面很多想法不一定成熟,也期待能尽快成长成Flutter老鸟,思考更多关于Flutter的实践。

参考资料:

Dart 概览 | Dart

Flutter architectural overview | Flutter

Flutter 架构概览 ( 中文文档)

Flutter实战(第二版)

带你全面了解 Flutter,它好在哪里?它的坑在哪里? 应该怎么学? - 专栏 - 声网 Agora RTC 开发者社区

Flutter vs Chromium 动画渲染的对比分析 - 知乎 (zhihu.com)

字节跳动为什么选用Flutter:并非跨平台终极之选,但它可能是不一样的未来 - Gityuan博客 | 袁辉辉的技术博客

Roadmap · flutter/flutter Wiki (github.com)

ocornut/imgui: Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies (github.com)

Flutter 新一代图形渲染器 Impeller_阿里巴巴淘系技术团队官网博客的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/22608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GIT安装以及详细操作流程

一、Git的安装 Git支持Linux、Windows和Mac系统,安装Git,可以到Git官方网站直接下载安装程序。 Git仓库的基本概念和流程 什么是版本库?版本库又名仓库,英文名repository,你可以简单的理解一个目录,这个目录里面的所…

element-plus表格添加简单右键

实现如下 <template><main class"mainClass" > <el-table :data"tableData" style"width: 100%"row-contextmenu"rowContextmenu"cell-contextmenu"cellContextmenu"contextmenu.prevent><el-table-c…

【全开源】Shopro社区团购(小程序版)

邻里间的购物新选择 基于Fastadmin后端管理系统Uniapp客户端&#xff08;仅支持微信小程序&#xff09;开发&#xff0c;生鲜果蔬社区团购的不二之选、快速搭建社区团购平台、让你的产品走进上千个社区。线上团购线下自提&#xff0c;玩转社区消费新模式提供专业、优质的社区团…

openh264 编码命令行工具源码分析

openh264 OpenH264 是由 Cisco 公司发布的一个开源的 H.264 编码和解码器。它提供了命令行工具&#xff0c;可以用于对视频进行编码和解码操作。 使用说明 openh264 编码命令行工具可以使用命令行或 config 配置进行编码操作。编译和使用方法具体可以参考 Windows11编译open…

easyexcel将csv转为excel处理数字问题

使用easyexcel可以将csv格式的文件转为.xlsx文件&#xff0c;但是csv中有很多数字&#xff0c;比如&#xff1a;"123","12.34","-111"&#xff0c;默认情况下会将其作为字符串写入.xlsx文件&#xff0c;就如同下面一样&#xff0c;字符类型的数字…

国产SDI/功能与GV7600/GS2972类似

是一款传递数字标清和高清信号的数字视频发送器&#xff0c;功能与GV7600/GS2972类似&#xff0c;集成了线缆驱动器&#xff0c;可以使用 75 欧姆的同轴线缆传递525i&#xff0c;625i&#xff0c;720P&#xff0c;1080P。 支持的速率如下&#xff1a; 如需更多资料请留言哦&am…

【Spring框架全系列】SpringBoot_3种配置文件_yml语法_多环境开发配置_配置文件分类(详细)

文章目录 1.三种配置文件2. yaml语法2.1 yaml语法规则2.2 yaml数组数据2.3 yaml数据读取 3. 多环境开发配置3.1 多环境启动配置3.2 多环境启动命令格式3.3 多环境开发控制 4. 配置文件分类 1.三种配置文件 问题导入 框架常见的配置文件有哪几种形式&#xff1f; 比如&#xf…

python11 序列的相关操作

枚举遍历 序列的相关操作 text "hello,python" # in 判断字符是否在序列中&#xff0c;存在返回true,否则返回false print(p是否存在:,(p in text)) print(a是否存在:,(a in text)) # not in 判断字符不在序列中&#xff0c;不存在返回true,否则返回false print(p不…

2024年数字化经济与金融创新国际学术会议(ICDEFI 2024)

2024年数字化经济与金融创新国际学术会议&#xff08;ICDEFI 2024&#xff09; 会议简介 2024年数字经济与金融创新国际学术会议即将召开。此次会议旨在汇集全球数字经济与金融创新领域的专家学者&#xff0c;共同探讨数字经济的发展趋势以及金融创新的路径。与会者将分享前沿…

如何理解 Java 8 引入的 Lambda 表达式及其使用场景

Lambda表达式是Java 8引入的一项重要特性&#xff0c;它使得编写简洁、可读和高效的代码成为可能。Lambda表达式本质上是一种匿名函数&#xff0c;能够更简洁地表示可传递的代码块&#xff0c;用于简化函数式编程的实现。 一、Lambda表达式概述 1. 什么是Lambda表达式 Lambd…

【STM32】STM32F103C6T6标准外设库

1、标准外设库获取 第一步&#xff0c;首先获取标准外设库&#xff0c;可以从官网进行下载。 https://www.st.com.cn/zh/embedded-software/stm32-standard-peripheral-libraries.html 根据自己的型号选择不同的系列&#xff0c;我这里选择是STM32F1系列 下载最新版本V3.6&a…

【QT5】<总览二> QT信号槽、对象树及样式表

文章目录 前言 一、QT信号与槽 1. 信号槽连接模型 2. 信号槽介绍 3. 自定义信号槽 二、不使用UI文件编程 三、QT的对象树 四、添加资源文件 五、样式表的使用 六、QSS文件的使用 前言 承接【QT5】&#xff1c;总览一&#xff1e; QT环境搭建、快捷键及编程规范。若存…

【最新鸿蒙应用开发】——一篇搞懂什么是UIAbility

UIAbility组件 UIAbility组件是一种包含UI的应用组件&#xff0c;UIAbility组件是系统调度的基本单元&#xff08;最小单元&#xff09;&#xff0c;为应用提供绘制界面的窗口&#xff0c;主要用于和用户交互。一个应用可以包含一个或多个UIAbility组件。 UIAbility的设计理念…

AI大模型应用开发实践:5.快速入门 Assistants API

快速入门 Assistants API Assistants API 允许您在自己的应用程序中构建人工智能助手。一个助手有其指令,并可以利用模型、工具和知识来回应用户查询。 Assistants API 目前支持三种类型的工具: 代码解释器 Code Interpreter检索 Retrieval函数调用 Function calling使用 P…

Java同步与线程安全,同步方法、同步块和java.util.concurrent包的使用

Java的同步与线程安全是并发编程中至关重要的部分。在多线程环境下&#xff0c;确保数据的一致性和避免竞态条件&#xff08;race condition&#xff09;是程序设计的关键。 一、Java中的线程安全 线程安全&#xff08;Thread Safety&#xff09;是指多线程环境下&#xff0c…

一键开启:盲盒小程序里的梦幻奇遇

在繁忙的都市生活中&#xff0c;每个人心中都藏着一个关于奇遇的梦想。如今&#xff0c;我们为您精心打造了一款盲盒小程序——“梦幻奇遇”&#xff0c;只需一键开启&#xff0c;就能带您走进一个充满无限惊喜和梦幻色彩的奇幻世界。 一、神秘盲盒&#xff0c;惊喜连连 “梦幻…

gitlab之cicd的gitlab-runner集成-dockerfile构建环境

目录 概述离线资源docker-compose问题 docker-compose问题1问题2 gitlab-runner集成gitlab 概述 cicd引文目录是想通过dockerfile构建 maven、jdk、docker环境的 gitlab-runner 运行环境。但docker最后测试的时候有点问题&#xff0c;且最后使用 kubectl 时有麻烦&#xff0c;所…

python--面向对象-文件读写-异常

一、继承 定义一个类时&#xff0c;需要使用另外一个类的方法或属性&#xff0c;就可以通过继承实现 object是Python的顶级类&#xff0c;创建类是会自动继承&#xff0c;就拥有object中的方法 定义格式 # 类的定义 # 旧式类定义 一般在定义单个类时使用 class 类名:name N…

Spring Boot 使用自定义注解和自定义线程池实现异步日志记录

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

如何保持气膜场馆内部空气新鲜—轻空间

气膜建筑作为现代建筑的一种新兴形式&#xff0c;以其独特的优势和设计受到了广泛欢迎。然而&#xff0c;保持气膜内部空气新鲜是一个必须解决的问题。我们通过配备先进的新风系统&#xff0c;提供了高效的解决方案。 新风系统的工作原理 气膜建筑内部空气的新鲜度主要依靠其配…