使用 GetX 进行 Flutter 状态管理

言鼎科技 2023-06-19 343

介绍

每当我们在 flutter 中开始构建任何应用程序时,我们都必须决定我们需要使用哪种状态管理。通过此博客,您可以更轻松地做出此决定。在这里,在这篇教程:Flutter state management using GetX 中,我想解释一下 GetX 这个强大的 flutter 框架。

什么是GetX?

状态管理允许您在应用程序内传输数据。每当传递数据时,应用程序的状态都会更新,从而重建系统。因此,开发人员必须特别小心地管理应用程序的状态,因为对于复杂的应用程序来说,状态更新有时看起来成本很高。

Flutter 传统上提供 Stateful Widget 来管理应用程序中的状态。但是,我们在使用有状态小部件时需要处理一些限制。

为了克服这些限制,我们可以选择使用 GetX 进行 Flutter 状态管理

GetX 是 Flutter 提供的用于管理状态及其更新的强大且轻量级的解决方案。它提供:

  • 高性能状态管理

  • 智能依赖注入

  • 快速实用的路线管理

为什么选择 GetX?

那么,让我们更深入地探讨一下为什么我们需要 GetX 来管理 Flutter 应用程序中的状态。GetX 在三个不同的标准上改进了 flutter 应用程序:

  • 生产力:开发人员可以借助简单的语法轻松实现 getx 状态管理 flutter。无论代码片段多么复杂,您都可以使用 GetX flutter 节省时间。它通过减少提供最佳性能的开发时间来提高生产率。

  • 组织和可读性:GetX 解耦视图。它提供了简单且不复杂的语法,从而提高了业务逻辑的可读性和格式。

  • 性能:如上所述,GetX 专注于如何消耗最少的资源,这有助于提高应用程序性能。它不使用 ChangeNotifier 或 Streams。查看下面描述各种状态管理器的 RAM 图表。


足够的理论部分。让我们继续使用 GetX 教程进行 Flutter 状态管理,并在我们的应用程序中实现它。


安装 GetX


flutter pub 添加获取

在Android studio/vs code的终端运行上面的命令,它会添加最新的GetX插件到pubspec.yaml.

我们将在这个进一步的教程中涵盖三个部分
1. 基本计数器应用程序的状态管理
2. 使用 GetX 进行导航
3. 在没有上下文的情况下扩充 UI 组件

提出您的需求,我们提供解决方案!
使用 Bacancy 开发最佳、具有成本效益和高性能的 Flutter 应用程序!停止浪费您的时间并联系我们聘请 Flutter 开发人员!

依赖注入

在 Getx 中,依赖注入允许您仅使用 1 行代码来放置/检索您的类实例,不需要上下文来放置/检索您的类实例。


获取.put(某些类());获取.lazyPut(() => SomeClass());

Get.put() 可帮助您在整个应用程序中激活您的实例。
而 Get.lazyPut 通过在屏幕需要时实例化类并稍后在不再需要时将其删除来帮助您管理应用程序内存。

Getx 绑定

该软件包的强大功能之一。通过使用它,您可以将屏幕连接到他们的控制器。因此,无论何时从小部件堆栈中移除屏幕,控制器中存在的所有流、变量和实例都将自动从内存中清除。

项目结构

每个屏幕都进入功能文件夹
在每一个屏幕上

  • 绑定:当屏幕可见时需要实例化的控制器列表

  • 控制器:业务逻辑

  • Repository:包含对外部数据源的调用

  • 路线:PageRoute(包含有关名称、屏幕和绑定的信息)

  • 查看:您的屏幕/小部件

使用 GetX 教程进行 Flutter 状态管理

在这里,我将通过使用控制器分离 UI 逻辑和业务逻辑来创建一个计数器应用程序,为此我将使用 Obx。如果您不知道这一切,请不要担心;我正在一一详细解释所有这些。


您可以看到我使用推荐的 GetX 模式创建的项目结构,其中包含视图、控制器和绑定类。View 类处理用于膨胀 UI 的代码,该 UI 将出现在屏幕上。绑定类将与特定页面关联,在该类中,我们可以实例化控制器类。在控制器类中,我们可以定义变量和业务逻辑函数,在我们的例子中是增量函数。此外,在 main.dart 中,我们声明了 GetMaterialApp 而不是 MaterialApp,因此我们可以使用 GetX 框架的所有功能。

CounterRepository 类


抽象类 CounterRepository {
 常量计数器库();
 处方药计数;
 无效增量();}类 CounterIncrementOneRepository 扩展 CounterRepository {
 CounterIncrementOneRepository();
 @覆盖
 最终处方计数 = 0.obs;
 最终 int _incrementValue = 1;
 @覆盖
 void increment() => count.value += _incrementValue;}

CounterRepository 提供了一种抽象,因此您可以在不影响您的表示层或业务逻辑层的情况下模拟底层数据源。

计数器控制器类


类 CounterController 扩展 GetxController {
 最终的 CounterRepository 回购;
 计数器控制器(this.repo);
 void navigateToReverseCounterScreen() {
   Get.offAllNamed(ReverseCounterRoute.name);
 }}

计数器控制器包含可在您的屏幕中使用的存储库实例和其他业务逻辑。这里我用.obs声明了count变量,这意味着count是可观察的,每当这个值发生变化时,我们可以通过控制器类监听那个值。与提供者不同,我们不需要调用notifylisteners。在增量函数中,我只是增加计数变量值。

反绑定类


类 CounterBinding 实现绑定 {
 常量计数器绑定();
 @覆盖
 无效依赖项(){
   Get.lazyPut(() => CounterController(CounterIncrementOneRepository()));
 }}

如前所述,Get.lazyPut() 可帮助您在需要时实例化您的控制器,例如当您的屏幕对用户可见时,并在您的屏幕从小部件堆栈中移除时移除控制器。

CounterRoute类


类 CounterRoute {
 常量 CounterRoute._();
 静态常量字符串名称 = '/';
 static const 绑定 binding = CounterBinding();
 static const 小部件屏幕 = CounterScreen();
 静态最终 GetPage 页面 = GetPage(
   姓名:姓名,
   绑定:绑定,
   页面:()=>屏幕,
 );
 静态 GetPageRoute 获取 pageRoute => GetPageRoute(
       设置:const RouteSettings(名称:名称),
       绑定:绑定,
       页面:()=>屏幕,
     );}

计数器路由包含您的路由相关信息,如名称、绑定和屏幕。

计数器屏幕类


类 CounterScreen 扩展 StatelessWidget {
 const CounterScreen({Key?key}) : super(key: key);
 @覆盖
 小部件构建(BuildContext 上下文){
   最终 CounterController 控制器 = Get.find();
   返回脚手架(
     应用栏:应用栏(
       title: const Text('计数器'),
     ),
     身体:中心(
       孩子:专栏(
         mainAxisAlignment:MainAxisAlignment.center,
         孩子们:[
           高架按钮(
             onPressed: controller.navigateToReverseCounterScreen,
             child: const Text('Go to reverse counter screen'),
           ),
           const SizedBox(高度:16),
           常量文本(
             '你已经按下按钮这么多次了:',
           ),
           对象(
             () => 文本(
               '${controller.repo.count.value}',
               样式:Theme.of(context).textTheme.headline4,
             ),
           ),
         ],
       ),
     ),
     浮动操作按钮:浮动操作按钮(
       onPressed: controller.repo.increment,
       工具提示:'增量',
       孩子:const Icon(Icons.add),
     ),
   );
 }}最终 CounterController 控制器 = Get.find();

上面一行提供了控制器的参考。

主要部分类

要使您的 getx 绑定工作,您需要在 GetMaterialApp -> getPage 属性中传递路由信息。在这里我们将使用我们已经创建的main.dart 的CounterRoute 类


无效主要(){
 runApp(const MyApp());}类 MyApp 扩展 StatelessWidget {
 const MyApp({super.key});
 @覆盖
 小部件构建(BuildContext 上下文){
   返回 GetMaterialApp(
     title: 'Flutter Getx 演示',
     主题:主题数据(
       primarySwatch: Colors.blue,
     ),
     initialRoute: CounterRoute.name,
     获取页面:[
       CounterRoute.page,
       ReverseCounterRoute.page,
     ],
   );
 }}

为了测试 getx 绑定,我创建了一个与计数器相同的第二个屏幕,但它是一个反向计数器,因此当用户单击减号按钮时,计数器将递减

这是反向计数器中使用的所有文件


反向计数器存储库(仅从计数器存储库更改)


抽象类 ReverseCounterRepository {
 const ReverseCounterRepository();
 处方药计数;
 无效递减();}类 ReverseCounterDecrementOneRepository 扩展 ReverseCounterRepository {
 ReverseCounterDecrementOneRepository();
 @覆盖
 最终处方计数 = 0.obs;
 最终 int _decrementValue = 1;
 @覆盖
 void decrement() => count.value -= _decrementValue;}

在这里您可以看到此存储库将值减一。这是在反向计数器屏幕中所做的唯一更改。


在这里,您可以看到当用户导航到计数器屏幕时创建和初始化 CounterController 的日志,以及当用户移动到新屏幕时从内存中删除的日志

反向计数器控制器也是如此 ReverseCounterController 在用户导航到反向计数器屏幕时创建和初始化,并在用户移动到新屏幕时从内存中删除

命名导航类

在你的 MaterialApp 之前添加“Get”,将其变成 GetMaterialApp
并分配 initialRoute 和 getPages


类 MyApp 扩展 StatelessWidget {
 const MyApp({super.key});
 @覆盖
 小部件构建(BuildContext 上下文){
   返回 GetMaterialApp(
     title: 'Flutter Getx 演示',
     主题:主题数据(
       primarySwatch: Colors.blue,
     ),
     initialRoute: CounterRoute.name, // 主页路由
     getPages: [ // 路由/屏幕在整个应用程序中可用
       CounterRoute.page,
       ReverseCounterRoute.page,
     ],
   );
 }}这里 CounterRoute.page 是静态最终 GetPage 页面 = GetPage(
   name: name, // 这个名字用来分配具名路由
   绑定:绑定,
   页面:()=>屏幕,
 );导航到命名路线使用Get.toNamed('/some_page');Get.offNamed('/some_page');Get.offAllNamed('/some_page');Get.offNamedUtil('/some_page');

final CounterController counterController = Get.put(CounterController());

在构建方法中使用上述语法,我已经定义了控制器类。文本按钮将调用控制器类中定义的增量方法,文本将显示计数的更新值。但是你能看到的主要是文本小部件用 Obx 包装,这意味着它可以获取可观察变量的值;没有 Obx,价值就不会得到体现。

在这里,我使用一个简单的计数器应用程序示例来轻松理解所有类、结构和状态管理。我们可以使用 GetX flutter 通过遵循这种可观察的模式并编写更清晰的代码来实现更多。

让我们深入到导航部分。

在状态管理块中附带的屏幕截图中,我们还创建了一个名为 home 的页面。因此,假设我们需要单击一次按钮从计数器类转到主页。我们可以简单地调用 GetX 导航块,如下所示。

Get.to(HomeView());

很简单。不是吗?无需调用大量样板代码,我们可以简单地调用它并移动到不同的屏幕。此外,还有不同的选项可以重定向到另一个页面。

例如,您可以简单地将主屏幕替换为下面当前打开的屏幕。这意味着将被替换的当前屏幕不会在堆栈中。

Get.off(HomeView());

而且,如果我们需要删除所有以前的堆栈,我们可以调用Get.off(HomeView());

Get.offAll(HomeView());

除此之外,我们可以在路由之间传递数据并在打开另一个路由之前显示动画,并使用 flutter GetX 打开一个屏幕作为对话框。

现在让我们转到没有上下文的 Inflating UI 组件的最后一点。

在没有上下文的情况下膨胀 UI 组件

传统上,打开对话框或底部工作表。如果您有一个单独的文件来处理通用小部件,我们还需要将上下文传递给该类。但是对于 GetX,情况并非如此。我们可以在不使用上下文的情况下以更简单的方式简单地膨胀那种 UI 块。

显示小吃店


Get.snackbar('This is snackbar', 'This is snackbar message', backgroundColor: Colors.red);

显示对话框


Get.defaultDialog(
  title: '这是对话',
  middleText: '这是中间文本',
  buttonColor: Colors.green,
  textCancel: "取消",
  textConfirm: "确认");

显示底页


Get.bottomSheet(
容器(
  孩子:包裹(
    孩子们: [
      列表块(
        领先:图标(Icons.wb_sunny_outlined),
        title: Text("浅色主题"),
        onTap: () => {Get.changeTheme(ThemeData.light())},
      ),
      列表块(
        领先:图标(Icons.wb_sunny),
        title: Text("深色主题"),
        onTap: () => {Get.changeTheme(ThemeData.dark())},
      )
    ],
  ),
),
背景颜色:Colors.green);

我想这就是 GetX 的目的。您可以通过以下官方链接来探索有关 GetX 的更多信息。
https://pub.dev/packages/get

借助 Git Cli 插件,您可以使项目结构更加顺畅。您可以查看下面的链接。
https://pub.dev/packages/get_cli

结论

以上就是使用 GetX 进行 Flutter 状态管理的教程。如果您是 Flutter 爱好者,Flutter 教程页面适合您!试用教程并开始在您的应用程序中实施它们。如果您有任何建议、疑问或问题,请给我们回信。

言鼎科技主做软件开发,微信小程序,网站开发,软件外包,手机APP开发。如有需要记得联系我们!

The End