Flutter和Dartea —轻松创建移动应用程序。

如果您厌倦了所有这些状态突变混乱,或者在调试一堆Rx东西时感到筋疲力尽,那么本系列文章非常适合您。 我将介绍创建移动应用程序的现代方法。 我相信这种方法有助于我们为UI编写干净,可维护,可伸缩和可预测的代码。 确实,这使我们作为开发人员更加快乐h

在本文中,我将与Flutter和Dartea会面。 而且,是的,我们将创建另一个柜台应用程序。

让我们从Flutter开始。 正如官方文件所说:“ Flutter是Google的移动应用SDK,可在创纪录的时间内在iOS和Android上制作高质量的本机界面。”是的,还有一个由Google支持的跨平台框架。 我不会显示和解释Flutter基本应用程序的每个部分,已经有很多关于该主题的博客文章和视频。 如果您对Flutter不太熟悉,那么此链接可能会有所帮助:

  • https://medium.com/flutter-community/in-plain-english-so-what-the-heck-is-flutter-and-why-is-it-a-big-deal-7a6dc926b34a
  • https://medium.com/fluttery/what-even-are-flutter-widgets-ce537a048a7d
  • https://medium.com/flutter-community/widget-state-buildcontext-inheritedwidget-898d671b7956

我们只看一下简单的HelloWorld应用程序,并快速了解主要概念和功能。

首先,我们需要按照以下说明下载并安装Flutter本身。 成功安装所有组件后,我们可以在终端“ flutter create hello_world”中使用简单命令创建新应用程序

让我们删除lib / main.dart中的所有内容并编写更简单的示例。

Flutter使用主要功能作为入口点。 在main内部,我们调用runApp并将HelloWorld类的实例传递给它。 HelloWorld是自定义的无状态小部件,它是Flutter的基本组件。 我们需要构建某种小部件树,以使Flutter的引擎在屏幕上呈现某些内容。 在内部构建方法中,我们组成了三个内置小部件: MaterialAppCenterText 。 我们应该看到这样的东西。

在这里可以找到有关Flutter的更多有用链接。

特色:

  • 它使用Dart作为主要语言
  • 编译为本机应用程序
  • 不依赖本机UI组件,而是通过Skia在Canvas上呈现所有内容
  • 使用不可变的小部件树(也称为虚拟圆顶)来描述在屏幕上绘制的内容。

我不是Dart编程语言的忠实拥护者,但在Flutter中使用它具有其他优势,例如热重载(一个人只需将dart文件保存在IDE中,然后在几秒钟内即可在真实设备上查看结果,这真棒)并将其编译成本机代码(不同于带有JS运行时的React Native)。

Flutter最重要的部分是不可变的声明性UI组合。 为什么这有关系? 两种本机平台(iOS和Android)都提供了用于创建和更新UI的命令式方法。 对于那些不了解声明式和命令式范式之间差异的人:

使用命令式方法时,我们说如何做,相反,使用声明式方法时,我们说该做什么。

例如,如果我们要隐藏进度指示器并显示一些数据。 使用命令式方法,我们可以这样做:

在这里,我们将命令发送到应用程序的View部分。 这些命令描述了我们到底要如何进行所需的更改:隐藏加载指示器,显示数据。

而且,如果要使用Flutter进行相同的声明,则可能看起来像这样:

在这里,我们可以看到UI部分( 构建方法)是完全声明性的。 它没有说如何更新UI,而是说了我们要渲染的内容,并且引擎知道如何处理它。 仍然,我们有一段命令性代码— onDataLoaded方法,我们可以轻松摆脱它,但是目前最重要的是如何使用声明性方法呈现和更新UI。

现在回到我们的问题:为什么重要? 因为使用创建UI的声明性方法,我们可以轻松地将视图与模型分离,并使视图尽可能哑。 这将给我们带来很多好处,例如可测试的UI逻辑和可预测的UI状态。 现在让我们讨论如何使其成为可能。

Dartea是Flutter的MVU或Elm体系结构(TEA)模式的实现。 下图描述了完整(差不多)应用程序的周期。

让我们创建一个简单的计数器应用程序来演示MVU体系结构的所有核心部分。

首先,我们需要添加dartea库作为依赖项。 在pubsec.yaml文件中,只需在依赖项部分添加dartea:^ 0.6.0

好的,现在我们可以开始创建模型了。

模型描述了我们应用的状态。 它应该是不可变的聚合数据结构。 Dart没有诸如记录(或Kotlin中的数据类)之类的不可变数据结构的内置语法,但是我们可以通过声明所有字段final并通过构造函数分配它们来模拟它。 同样在这里,我们添加了copyWith方法这是Dart中的通用模式,用于仅更新不可变类中的特定字段。

接下来,我们需要描述如何对我们的模型进行突变。 这应该通过消息来完成。 每个可以改变应用程序状态的事件都应描述为message 。 我们简单的计数器模型可以递增递减

理想情况下,消息应为求和类型或带标记的并集。 由于Dart不支持任何代数数据类型,因此我们可以通过一个通用的空抽象类对其进行仿真。

下一步可能是查看功能。

视图是纯函数,需要三个参数。 第一个论点是Flutter的上下文,在某些情况下可能有用。 最后一个论点是当前模型,我认为这里很清楚。 最有趣的是第二个参数。 调度是接收消息并将其分发到Dartea引擎的功能。 例如,在这里我们处理按钮的onPressed动作并调度增量/减量消息。 关于MVU(以及所有单向数据流体系结构)的最酷的事情是,调度消息是改变状态的唯一方法。 我们只要查看所有消息并了解我们所拥有的突变类型即可。 视图功能的结果是一个小部件 。 简单明了:将当前模型映射到UI元素树。 确实,这是声明性的。 UI元素没有任何突变或任何副作用。 幸运的是,在Flutter中,我们使用不可变的小部件树来构成UI场景。

很好,那么我们需要对消息做出反应并改变我们的模型 。 这就是更新功能的作用。

它需要当前模型和一条消息。 在该函数中,我们只检查消息的类型并相应地更改模型。 该函数的结果是Upd类,但是我们将在本系列的下一部分中稍后进行讨论。 然后新模型进入查看功能,并且循环不断重复。 而已。 更新函数也是纯函数,它不是真正更新模型 ,而是创建一个新模型(模型是不可变的,还记得吗?)。

好的,现在我们需要将所有内容放在一起。

要将所有MVU组件连接在一起,我们可以使用Program类。 它是Dartea库中的必不可少的类,它具有描述和运行应用程序所需的一切。 我们将三个函数传递给程序的构造函数: init,update,view。 我们刚刚讨论了其中两个,在这里我们只谈init几句话。

初始化函数用于创建应用程序的初始状态,此处我们使用0计数器初始化模型。

好的,我们创建了程序实例,然后需要在UI上显示一些内容。 为此,我们创建了无状态小部件CounterApp并将程序传递给它。 然后在内部构建中,我们创建一些基本的shell,并在最终调用program.build()方法中,它返回可以安装到树中的小部件。 而已。 现在我们的应用程序已启动并正在运行。

哇,行得通!

完整的源代码可以在这里找到。

让我们总结一下。

  1. 模型 -不可变的数据对象。 包含所有应用程序状态。
  2. View —纯函数,将当前模型映射到Widgets树。
  3. 更新 —纯函数,它接收一条消息(“刚刚发生的事情”)和当前模型,并返回新模型。

应用程序的所有核心组件都是纯净的并且是不变的。 让我们计算一下好处:

  1. 清晰分离模型 (应用程序状态), 视图和状态突变逻辑( 更新 )。 我们知道状态只能在更新函数中更改,而视图函数仅负责将当前状态映射到UI部件树。
  2. 不可变模型使我们有信心在此刻或那一刻我们的状态是有效的。
  3. 纯函数真的很容易测试和编写。

缺点:

  1. Dart不支持开箱即用的不变性。 因此,我们必须做一些额外的工作才能实现它。
  2. 使用消息(事件)和不可变模型对应用程序进行建模需要一些样板代码。 即使价格不太昂贵,我们也必须支付这个价格。

在接下来的文章中,我将创建一个用于浏览GitHub存储库的简单应用程序,我们将面对基本的移动开发例程,例如显示列表,发出http请求,导航等。

感谢您的关注并继续关注!


Shilyagov Pavel(@ShilyagovPavel)| 推特

Shilyagov Pavel(@ShilyagovPavel)的最新推文

twitter.com

Flutter社区(@FlutterComm)| 推特

Flutter社区(@FlutterComm)的最新推文。 跟随以获取来自…的新文章和包裹的通知。

twitter.com