Flutter GetX 状态管理

2025-06-07

Flutter GetX 状态管理

Flutter 无疑是开发跨平台应用的最佳框架。使用 Flutter 开发应用非常棒,而且非常简单,因为它提供了丰富的可自定义小部件。然而,一些状态管理选项会让您无法真正感受到 Flutter 框架的强大功能,因为您必须浪费开发时间来实现不必要的样板代码。当我开始学习 Bloc 模式时,我对 Bloc 的概念感到困惑,觉得它很难理解。另一方面,提供程序很容易理解,但我们必须非常小心地避免不必要的重建,因为它会直接影响应用程序的性能。然而,所有状态管理选项都有其优缺点。

GetX 秉持着不同的理念。它致力于以简洁、有序的方式管理应用程序状态,同时提升性能。那么,让我们看看 GetX 是如何实现这一目标的。

在本文中,我将讨论,

  1. GetX 为何如此特别?
  2. 使用 GetX 进行状态管理
  3. GetxController
  4. GetX 中的反应状态管理器
  5. GetX 中的简单状态管理器
  6. MixinBuilder:混合两种状态管理器
  7. StateMixin

GetX 为何如此特别?

GetX 不仅仅是一个状态管理库。事实上,它是一个小型 Flutter 框架,能够处理 Flutter 应用程序中的路由管理和依赖注入。但在本文中,我将仅讨论其状态管理功能。GetX
是一个非常轻量级且功能强大的 Flutter 状态管理解决方案。那么,GetX 为何如此出色呢?

高性能: GetX 尽可能减少资源使用。它不依赖于 Streams 或 ChangeNotifier,而是使用低延迟的 GetValue 和 GetStream 来提升性能。

更少的代码:您可能厌倦了在块模式中实现样板代码,并将开发时间浪费在不必要的代码上。时间就是金钱,对吧?在 GetX 中,您无需编写任何样板代码。在 GetX 中,您可以更快地完成相同的操作,并且代码更少。无需为状态和事件创建类,因为这些样板代码在 GetX 中不存在。

无需代码生成:完全无需使用代码生成器。这样,您宝贵的开发时间就无需再在每次修改代码时都运行代码生成器 (build_runner) 了。是不是很酷?

不用担心上下文:你的应用程序上下文非常重要。但是,将上下文从视图发送到控制器有时会很麻烦。在 GetX 中,你无需这样做。你可以在另一个控制器中访问其他控制器,而无需任何上下文。很酷吧?

避免不必要的重建:不必要的重建是基于 ChangeNotifier 的状态管理器的一个问题。当您在 ChangeNotifier 类中进行更改时,所有依赖于该 ChangeNotifier 类的控件都会被重建。有些重建可能是不必要的,而且成本高昂,还可能降低应用程序的性能。但在 GetX 中您无需担心这个问题,因为它根本不使用 ChangeNotifier。

代码组织简单: Bloc 的流行源于其卓越的代码组织能力。它使业务逻辑与表示层分离变得更容易。正如官方文档所述,GetX 是这一理念的自然演进。在 GetX 中,你不仅可以分离业务逻辑,还可以分离表示层。很强大吧?

那么,你觉得 GetX 怎么样?我能说它很优秀吗?我想是的。

使用 GetX 进行状态管理

GetX 提供两种状态管理器:响应式状态管理器和简单状态管理器。如果您之前使用过 Bloc,那么您应该具备一定的响应式编程经验。与 Bloc 不同,GetX 能够提供更出色、更便捷的响应式体验。简单状态管理器类似于在 StatefulWidget 中使用 setState,但方式更简洁。在讨论这两种状态管理器之前,有必要先了解一下GetxControllerGetX 的相关内容。

GetxController

您的控制器包含所有业务逻辑。GetX 有一个重要的类,名为GetxController。在控制器中启用响应式和简单的状态管理器功能非常有用。您只需从 GetxController 扩展您的控制器即可。

让我们从您的购物应用中举一个简单的例子。

class ProductController extends GetxController {
    // your state variables
    // your methods
}
Enter fullscreen mode Exit fullscreen mode

您可以使用 GetxController 完全移除 StatefulWidget。由于 GetxController 拥有onInit()onClose()方法,因此您可以替换StatefulWidget 中的initState()dispose()方法。很巧妙吧?当您的控制器在内存中创建时,会立即调用 onInit() 方法,而当控制器从内存中移除时,则会调用 onClose() 方法。

您也可以使用onReady()GetxController 中的方法。当 Widget 在屏幕上渲染后, onReady() 方法将被调用。

class ProductController extends GetxController {

     @override 
    void onInit() {
       // Here you can fetch you product from server
       super.onInit();
    }

    @override 
    void onReady() {
       super.onReady();
    }

    @override
    void onClose() { 
          // Here, you can dispose your StreamControllers
          // you can cancel timers
          super.onClose();
    }
}
Enter fullscreen mode Exit fullscreen mode

得益于DisposableInterface,GetxController 可以自行从内存中释放控制器。因此,您无需再手动释放任何控制器。GetxContoller 将为您处理所有事务。因此,它有助于减少内存消耗并提升应用程序性能。

GetX 中的反应状态管理器

响应式状态管理器以更简单、更简洁的方式实现了响应式编程。您可能在响应式编程方法中使用过 StreamContollers 和 StreamBuilder。但在 GetX 中,您无需创建这些东西。此外,与 Bloc 不同,您无需为每个状态创建单独的类。您可以删除这些样板代码,使用 Getx 只需几行代码即可完成相同的操作。

创建反应变量

在 GetX 的响应式方法中,首先需要创建可观察变量(响应式变量)。简单来说,您的小部件可以观察变量的变化。小部件可以根据这些变量的变化更新其 UI。创建响应式变量有三种不同的方法。

1. 将 Rx 附加到变量类型, Rx{Type}

class CounterController extends GetxController {
    var counter = RxInt(0);  // You can add 0 as the initial value
} 
Enter fullscreen mode Exit fullscreen mode

2. 使用 Rx 和 Dart 泛型 Rx<Type>

class CounterController extends GetxController {
    var counter = Rx<Int>(0);  // You can add 0 as the initial value
} 
Enter fullscreen mode Exit fullscreen mode

3. 添加.obs到末尾

class CounterController extends GetxController {
    var counter = 0.obs; 
}
Enter fullscreen mode Exit fullscreen mode

就是这样。很简单吧,你可以使用任何你喜欢的方法。

使用GetXObx

您可以使用GetXObx监听小部件中响应式变量的变化。
GetX<Controller>它类似于 StreamBuilder,但没有样板代码。
Obx比 GetX 简单得多。您只需用它来包装您的小部件即可。

class CounterController extends GetxController {
    var counter = 0.obs; 
}  
Enter fullscreen mode Exit fullscreen mode

使用 GetX:

GetX<CounterController>(
    init: CounterController(),
    builder: (controller) => Text(
         'Counter is ${controller.counter.value}'
    ),
),
Enter fullscreen mode Exit fullscreen mode

使用 Obx:

Obx(() => Text(
        'Counter is ${controller.counter.value}'
    ),
),
Enter fullscreen mode Exit fullscreen mode

value访问反应变量的值时必须使用其属性,例如controller.counter.value

class CounterPage extends StatelessWidget {

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


     @override
     Widget build(BuildContext context) {
        return Scaffold(
          body: Container(
             child: Center(
                child: Obx(() => Text(
                      'Counter is ${controller.counter.value}'
                    ),
                    ),
              ),
            ),
           );
        }
}
Enter fullscreen mode Exit fullscreen mode

使用 Obx 时,您可以利用 GetX 依赖注入。GetXPut中的方法用于管理 Flutter 项目中的依赖项。它可以帮助您在所有子路由中使用相同的控制器实例。将 CounterController 实例导入到您的 Widget 后,您可以将其用作 Obx 的控制器。

GetX 中的简单状态管理器

简单状态管理器占用极低的资源,因为它不使用 Streams 或 ChangeNotifier。但是,借助该update()方法,您的小部件可以监听状态的变化。在控制器中对状态进行一些更改后,您必须调用 update 方法来通知正在监听状态的小部件。

class CounterController extends GetxController {
    int counter = 0;

    void increment() {
        counter++;
       update(); // Tell your widgets that you have changed the counter
    }
}
Enter fullscreen mode Exit fullscreen mode

可以看到,我们只需像平常一样声明状态变量即可。与响应式变量不同,您无需将状态变量转换为其他变量(在响应式方法中,我们需要使用 .obs 声明响应式变量)。

获取生成器

GetBuilder小部件将根据您的状态变化更新您的视图。

GetBuilder<CounterController>(
    init: CounterController(),
    builder: (controller) => Text(
             'Counter: ${controller.counter.value}'
    ),
), 
Enter fullscreen mode Exit fullscreen mode

如果您在 GetBuilder 中首次使用某个控制器,则必须先初始化它。之后,您无需在另一个 GetBuilder 中再次启动同一个控制器。因为所有依赖于同一个控制器的 GetBuilder 都会在整个应用程序中共享同一个控制器实例。这就是简单的状态管理器极低内存消耗的原因。简单来说,如果 100 个 GetBuilder 使用同一个控制器,它们将共享同一个控制器实例。同一个控制器不会有 100 个实例。

class CounterController extends GetxController {
    int counter1 = 0;
    int counter2 = 0;

    void incrementCounter1() {
        counter1++;
        update();
    }

    void incrementCounter2() {
        counter2++;
        update();
    }
}
Enter fullscreen mode Exit fullscreen mode
GetBuilder<CounterController>(
    init: CounterController(), /* initialize CounterController if you use 
                                     it first time in your views */
    builder: (controller) {
             return Text('Counter 1: ${controller.counter1.value}'); 
       }
    ),



   /* No need to initialize CounterController again here, since it is 
      already initialized in the previous GetBuilder */
GetBuilder<CounterController>(                            
    builder: (controller) {
             return Text('Counter 2: ${controller.counter2.value}'); 
       }
    ),
Enter fullscreen mode Exit fullscreen mode

如果您使用 GetBuilder,则不再需要在应用程序中使用 StatefulWidget。与 SetState 相比,使用 GetBuilder 可以更简洁、更轻松地处理短暂状态(UI 状态)。简而言之,您可以将类设置为 StatelessWidget,只需将特定组件包装在 GetBuilder 中即可更新它们。仅此而已。您无需将整个类设置为 StatefulWidget,从而浪费资源。

MixinBuilder:混合两种状态管理器

混合MixinBuilder了两种状态管理器。因此您可以同时使用它们ObxGetBuilder但请注意,MixinBuilder 比其他两种方法消耗更多资源。如果您真的关心应用程序性能,请尽量少用 MixinBuilder。另一方面,MixinBuilder 的用例很少。

class CounterController extends GetxController {
    var counter1 = 0.obs; // For reactive approach
    int counter2 = 0;    // For simple state management approach

    void incrementCounter1() {
      counter1.value++;
    }

   void incrementCounter2() {
       counter2++;
       update();
    }
}
Enter fullscreen mode Exit fullscreen mode
MixinBuilder<CounterController>(
    init: CounterController(),
    builder: (controller) => Column(
       children: [
           Text('Counter 1: ${controller.counter1.value}), 
                         // For reactive approach

           Text('Counter 2: ${controller.counter2}') 
                       // For simple state management approach
        ]
    ),
),
Enter fullscreen mode Exit fullscreen mode

StateMixin

执行异步任务时,您可以使用StateMixin来更高效、更简洁地处理 UI 状态。
假设您的应用要从云服务器获取一些产品。因此,此异步任务需要一定的时间才能完成。因此,您的应用状态将根据异步任务的响应进行更改。

加载状态:在收到响应之前,您必须等待。
成功状态:您已收到预期的响应。
错误状态:执行异步任务时可能会发生一些错误

这些是应用程序执行异步任务时的主要​​状态。因此,StateMixin 可以帮助你根据这些状态和状态变化来更新 UI。

您只需使用with关键字将 StateMixin 添加到控制器即可。您还应该指定 StateMixin 要处理的状态类型,例如StateMixin<List<Product>>

class ProductController extends GetxController with StateMixin<List<Product>> {}
Enter fullscreen mode Exit fullscreen mode

并且RxStatus该类还提供了与 StateMixin 一起使用的定义状态。

RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('error message');
Enter fullscreen mode Exit fullscreen mode

StateMixin 提供了Change()方法,它会根据异步任务的响应来更改状态。你只需要传递新的状态和状态值即可。

change(newState, status: RxStatus.success());
Enter fullscreen mode Exit fullscreen mode

让我们举个例子。

class ProductController extends GetxController with StateMixin<List<Product>>{

    @override
    void onInit() {
        fetchProducts();
        super.onInit();
    }


    void fetchProducts() async {
          // You can  fetch products from remote server
        final response = await fetchProductsFromRemoteServer(); 

        If(response.hasData) {
            final data = response.data;
           //..
              // Successfully fetched products data
          change(data, status: RxStatus.success());     

          } else if(response.hasError) {
              // Error occurred while fetching data
          change(null, status: RxStatus.error('Something went wrong')); 

          } else {
              // No products data
          change(null, status: RxStatus.empty());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

如你所见,在收到包含数据的成功响应后,我通过将响应data和 传递RxStatus.success给 change() 方法来更改状态。同样,我也根据错误响应和空响应数据更改了状态。

class ProductsPage extends StatelessWidget {


    // Get a ProductController instance
    final ProductController controller = Get.put(ProductController());


    @override 
    Widget build(BuildContext context) {
        return Scaffold(
            // app bar

            body: controller.obx(

                (productsState) => ShowProductList(productsState),

            onLoading: CustomLoadingIndicator(),

            onEmpty: Text('No products available'),

            onError: (error) => Text(error),

            )
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

controller.obx()小部件会根据状态和状态的变化来更改您的 UI。
当异步任务启动(从服务器获取产品)时,obx小部件将显示默认的加载指示器。您还可以将 设置CustomLoadingIndicator()onLoading属性。
成功获取数据后,obx小部件将使用自定义小部件将数据渲染到 UI ShowProductList()
如果出现错误,默认情况下,obx小部件将渲染一个 Text 小部件来显示错误。您也可以将自定义错误小部件设置为onError属性。(请注意,controller.obx()这里的小部件与您在 Reactive 中学习到的小部件完全不同Obx())。

结论

当你在下一个项目中使用 GetX 时,你就会意识到它有多棒。本文的主要目标是快速概述 GetX。GetX 的首要任务是提高应用程序性能,同时以简单且井然有序的方式管理状态。

您可以从官方文档中阅读有关 Getx 的更多信息

文章来源:https://dev.to/gunathilakahashan10/getx-a-superior-state-management-in-flutter-4jcl
PREV
Evitando o Prop Drilling no React - Um Guia Prático
NEXT
规划你的第一个副业项目的计划