初尝Flutter
我是大概这周的前几天知道Dart 2要推出而且Flutter进入Beta的。
说实话,Dart我有所耳闻,虽然我是一个Google的粉丝,但是话还是要说清楚,我真不认为Google在设计语言上有什么优势,甚至是并不擅长设计语言的(Go语言我浅尝辄止),而且Dart本身设计我认为也有问题(居然同时存在const
和final
关键字),我也只是粗略的看了一下语法就停了。
然而,在今晚的旅程过后,我决定把Flutter和Dart加进学习日程表(虽然优先级不会太高),因为Flutter颠覆了我这个“零经验”移动开发者的观念。这篇文章,就让我零零散散的谈谈今晚的旅程。
0x00. What is Flutter?
那首先,什么是Flutter?
在讲Flutter之前,我们不得不提React Native,熟悉前端和移动端开发的同学肯定对这个东西有所了解。React Native是由Facebook在两年前推出的一套跨平台开发框架,使用React+JavaScript的组合来开发移动端应用。
当年我听说RN的原因是它的热更新:这套机制允许我们不用更新应用本身,而是通过云端推送更新的方式来对应用做出更新。
RN的出现的确给移动端开发掀起了一轮新的浪潮:跨平台、热更新、JavaScript。这样的组合,无论是对前端开发者还是移动端开发者都是极具吸引力的。同样,不少公司已经采用了这套框架,如我们熟悉的QQ Android端和手机京东iOS&Android端。
RN这一套机制实际上很容易猜测到的:底层是一个native app,这一个app负责进行传统的系统交互,比如调用startIntent()
方法等,然后上层是一个javascript bridge,这一个东西是一个桥梁,负责和底层的native app以及上层的表现层交互。上层的表现层就是用户看到的内容,不同框架的实现机制不同。
在RN之后出现的框架有:Weex、cordova等,以及,Flutter。
在2015年的Dart developer summit上,“Sky”,也就是现在的Flutter被首次提出,然后在2017年Google I/O上亮相之后,与近期推出了Beta。
Flutter的底层实现比起上述的框架们又有所不同:它不再需要任何的Bridge,而是通过一个C++写就的高性能底层框架来进行以下两种操作:UI绘制和事件监听。
而且,Flutter还有另一个特性:没有使用任何系统自带的组件,而是自己实现了组件库(Widgets),这样一来,UI 本身不需要去适配平台,而是只需要做好渲染层和平台的连接即可,实现同样的效果的成本也就更低。
这样一来,Flutter就和上述的以React Native为首的框架不同,不仅具有高性能,同时还有出色的、漂亮的、大量可复用的UI组件,能够帮助我们快速开发跨平台的移动端应用。这无疑是极具吸引力的。同时,Flutter也将成为Google最新的操作系统,Google Fuchsia的默认开发语言。
关于Flutter的讨论还有很多,文末一并附上。
讲了这么多,下面来实际演练一下。
0x01. SDK安装与编辑器配置
SDK的安装实际上是比较简单的,一波三折的部分主要在Android开发工具链的配置上。
1. Flutter SDK
首先要注意的是,Dart本身已经被包含在Flutter内,不需要安装Standalone的Dart VM。
对于中国用户,Dart Team很友好的提供了加速安装的方法:
|
|
执行完以上命令后,flutter会自动生成一个报告来告诉你的本机配置如何,缺失什么配什么。
这里我缺Android工具链(换到Manjaro之后没有配置Android开发环境——因为我在Elemenrtary下就没写过Android),所以我经历了痛苦的Android SDK配置过程。这个安装大家各显神通,要写就应该是另一篇文章了。
之后是配置Flutter工具链。工具链配置其实就是老路子:修改环境变量。
|
|
重启一下终端,安装就完成了。
要注意的是,上面设置的镜像https://pub.flutter-io.cn
是临时性的,这里强烈建议大家把镜像也一起添加进去,不然之后装包的时候会各种卡死。
|
|
要注意的是,官方提示到这个镜像是由GDG China负责维护的,Flutter团队并不保证可用性,所以各位记得出现了问题及时更换镜像。
2. VS Code配置
官方推荐的开发工具有两个:Android Studio和VS Code。作为VS Code重度用户,我当然选择了VS Code。
VS Code的配置完全没有任何难度,来到扩展中心安装dart code
即可。
之后使用命令面板Flutter: New Project
新建一个Flutter项目,就可以开始愉快的Flutter开发之旅了~
注意,开发Flutter需要使用Android或者iOS模拟器,iOS我不知道,对于Android,如果你在Windows下,使用任何模拟器并正常连接ADB就行;如果在Linux下,要么就再开一个Android Studio启动一个模拟器,要么就直接使用Android Studio开发,要么就像我一样,直接上真机。(Android Studio + 模拟器真的吃内存,我要报警了。
0x02. 官方示例分析
让我们分析一下官方示例项目的一个简单结构:
|
|
首先,一个程序的入口一定是main()
,在Dart中,这个函数是没有任何返回值的。对于第三行的这个写法,实际上是如下写法的简写:
|
|
那这其实就是一个语法糖,创建单语句函数的语法糖。
然后是包的导入。要注意的是,导入第三方包的结构是:
|
|
我们继续:
|
|
这一段语法很像Java,让我们来看看这里面几个值得注意的点:
UI层的基本单位是一个组件(
Widget
),即使是最底层的App
也不例外。构造函数中的如下写法:
1
return new MaterialApp(title: 'Flutter Demo', //...)
Python同学应该一眼就能看出来:关键字参数。Dart的参数支持如上所示的关键字参数来对一些关键属性做一种Mapping指定。
这个
MyApp
继承自StatelessWidget
,字面意思上来看,这是一种“无状态组件”,和下面的“有状态组件”其实是一种对应关系,我们下面讲。一个组件创建要提供的一个必要方法是
build(BuildContext context)
,每当这个组件被重绘的时候都会调用这个方法。
|
|
这个组件就是一个“有状态组件”,有状态组件的重绘使用的是createState()
,创建状态。
对于“有状态组件”,我们都要实现一个状态类来控制状态:
|
|
上面这个类做了什么?我们一步步拆分:
类信息:
这个类是
MyHomePage
的状态,所以自然是继承自State<MyHomePage>
这个类;这个类提供了两个函数:代理函数_incrementCounter
和必要的build
函数;一个计数器变量_counter
。_incrementCounter
函数:这个函数很明显,每次调用的时候使用
setState()
来改变状态,setState()
接受一个函数作为参数,这个函数就是很简单的一个闭包,每次让计数器+1。build
函数:那这里其实很简单,根据绘制树绘制一个
Scaffold
组件,包含两行文字和一个浮动按钮,浮动按钮监听按下事件,每次按下的时候执行_incrementCounter
函数。
类的信息分析完了,接下来我们来分析两个重要的东西:有无状态和setState()
。
首先要明确一点,在Flutter中,任何组件都是不可变的(Immutate),这意味着一旦一个组件被绘制完毕,没有任何办法来修改这个组件当前状态。
无状态组件,也就意味着这个组件永久不可变,也就是说,这个组建的状态只有你在代码中写好的一种状态,无论如何不会发生改变。
有状态组件的改变,实际上并不是组件发生了改变,而是我们重绘了全新状态下的组件。也就是说,实际上的StatefulWidget
是一个代理,作为真正的状态的一个代理。当状态发生了改变,Flutter会调用状态的build
函数,然后把新的状态组件提供给StatefulWidget
,然后绘制到表现层。
那么这里的setState()
其实就很简单了,就是执行参数这个函数并通知框架状态发生了改变,框架调用build
来重绘组件。值得注意的是,在其他地方做出修改系统并不会重绘,也就是说,通知系统状态改变的入口一定是setState()
以及相应的一些其他函数。
换一个说法,StatefulWidget
是State
的一个实例,State
组件本身在整个应用的生命周期都能存活。
分析完这里,我们再来讨论几个有趣的小细节:
- Flutter万物皆组件,连
Center
、Column
和MainAxisAlignment
也是组件,我们并没有设置任何“属性”,而是选择了属性对应的“组件”。 - 支持字符串替换:
'$_counter'
,十分方便的一种字符串表示方法。
这就是这个demo给我们提供的全部信息了。
从上面的分析来看,Flutter的设计模式十分像React的那一套,整个过程是响应式的:根据用户的请求响应来处理业务和重绘UI,这一套设计模式也被证明在界面构筑上是一套十分高效的设计模式。
Dart的类Java和C++语法也让人很好上手,对闭包和匿名函数的支持也在意料之内。
如果感觉意犹未尽的话,这里还有Flutter官方的小教程,有时间我也会对这个教程进行分析,不过这个教程体现的信息实际上并不比这个demo多多少。
0x03. Then
毫无疑问,Flutter又是移动端一个新兴强势势力,而且背后是Google,Android的父亲,这样我们不用担心Flutter的未来发展路线,至少在官方扶持下,Flutter不会只是一个昙花一现的框架。
但是在现在的世界上,能保持一个项目活力的关键并不是后台多么硬,而是开源社区的活跃程度。Flutter是一个十分不错的框架,尤其是大部分代码都可以自定义的情况下,很容易hack进去根据自己的需要进行修改。官方层面上,无论是整个开发工作流、对Issue的响应速度还是对开源社区的友好程度都是一种很积极的状态,越来越多的包也进入了dart的包管理系统。
然而,业界仍然对于Flutter有不同的声音,既有看好的也有看衰的,我们似乎不能现在就对Flutter的命运下一个定论。同时,Dart这门语言我的评价仍然不高,很多地方的设计并没有很好的解决Java和C++的遗留问题,这可能也将成为Flutter发展的一个阻碍。
那从我个人角度来看,这一句话是我想说的:I’m going to fix an eye to Flutter.
作为一个“零经验”移动端开发者,Flutter惊艳了我,让我重拾了对移动端开发的热情。虽然Dart有很多不尽如人意的地方,虽然没有太多的包可用,但是Flutter的未来仍然是一片光明的状态。
所以,还有什么理由不立即开始学习Flutter呢?
致谢:这篇文章的几张图片来自InfoQ的为什么说Flutter是革命性的?,感谢,同时,这篇文章也很值得一读。
延伸阅读:知乎上关于Flutter的讨论有很多大牛参与了,兼听则明,很多回答的质量十分高,建议一条一条仔细看。
未来我应该也会写更多关于Flutter的文章,之后见~