Flutter GetX 状态管理
Flutter 无疑是开发跨平台应用的最佳框架。使用 Flutter 开发应用非常棒,而且非常简单,因为它提供了丰富的可自定义小部件。然而,一些状态管理选项会让您无法真正感受到 Flutter 框架的强大功能,因为您必须浪费开发时间来实现不必要的样板代码。当我开始学习 Bloc 模式时,我对 Bloc 的概念感到困惑,觉得它很难理解。另一方面,提供程序很容易理解,但我们必须非常小心地避免不必要的重建,因为它会直接影响应用程序的性能。然而,所有状态管理选项都有其优缺点。
GetX 秉持着不同的理念。它致力于以简洁、有序的方式管理应用程序状态,同时提升性能。那么,让我们看看 GetX 是如何实现这一目标的。
在本文中,我将讨论,
- GetX 为何如此特别?
- 使用 GetX 进行状态管理
- GetxController
- GetX 中的反应状态管理器
- GetX 中的简单状态管理器
- MixinBuilder:混合两种状态管理器
- 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,但方式更简洁。在讨论这两种状态管理器之前,有必要先了解一下GetxController
GetX 的相关内容。
GetxController
您的控制器包含所有业务逻辑。GetX 有一个重要的类,名为GetxController
。在控制器中启用响应式和简单的状态管理器功能非常有用。您只需从 GetxController 扩展您的控制器即可。
让我们从您的购物应用中举一个简单的例子。
class ProductController extends GetxController {
// your state variables
// your methods
}
您可以使用 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();
}
}
得益于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
}
2. 使用 Rx 和 Dart 泛型 Rx<Type>
class CounterController extends GetxController {
var counter = Rx<Int>(0); // You can add 0 as the initial value
}
3. 添加.obs
到末尾
class CounterController extends GetxController {
var counter = 0.obs;
}
就是这样。很简单吧,你可以使用任何你喜欢的方法。
使用GetX
和Obx
您可以使用GetX
或Obx
监听小部件中响应式变量的变化。GetX<Controller>
它类似于 StreamBuilder,但没有样板代码。Obx
比 GetX 简单得多。您只需用它来包装您的小部件即可。
class CounterController extends GetxController {
var counter = 0.obs;
}
使用 GetX:
GetX<CounterController>(
init: CounterController(),
builder: (controller) => Text(
'Counter is ${controller.counter.value}'
),
),
使用 Obx:
Obx(() => Text(
'Counter is ${controller.counter.value}'
),
),
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}'
),
),
),
),
);
}
}
使用 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
}
}
可以看到,我们只需像平常一样声明状态变量即可。与响应式变量不同,您无需将状态变量转换为其他变量(在响应式方法中,我们需要使用 .obs 声明响应式变量)。
获取生成器
该GetBuilder
小部件将根据您的状态变化更新您的视图。
GetBuilder<CounterController>(
init: CounterController(),
builder: (controller) => Text(
'Counter: ${controller.counter.value}'
),
),
如果您在 GetBuilder 中首次使用某个控制器,则必须先初始化它。之后,您无需在另一个 GetBuilder 中再次启动同一个控制器。因为所有依赖于同一个控制器的 GetBuilder 都会在整个应用程序中共享同一个控制器实例。这就是简单的状态管理器极低内存消耗的原因。简单来说,如果 100 个 GetBuilder 使用同一个控制器,它们将共享同一个控制器实例。同一个控制器不会有 100 个实例。
class CounterController extends GetxController {
int counter1 = 0;
int counter2 = 0;
void incrementCounter1() {
counter1++;
update();
}
void incrementCounter2() {
counter2++;
update();
}
}
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}');
}
),
如果您使用 GetBuilder,则不再需要在应用程序中使用 StatefulWidget。与 SetState 相比,使用 GetBuilder 可以更简洁、更轻松地处理短暂状态(UI 状态)。简而言之,您可以将类设置为 StatelessWidget,只需将特定组件包装在 GetBuilder 中即可更新它们。仅此而已。您无需将整个类设置为 StatefulWidget,从而浪费资源。
MixinBuilder:混合两种状态管理器
混合MixinBuilder
了两种状态管理器。因此您可以同时使用它们Obx
。GetBuilder
但请注意,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();
}
}
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
]
),
),
StateMixin
执行异步任务时,您可以使用StateMixin
来更高效、更简洁地处理 UI 状态。
假设您的应用要从云服务器获取一些产品。因此,此异步任务需要一定的时间才能完成。因此,您的应用状态将根据异步任务的响应进行更改。
加载状态:在收到响应之前,您必须等待。
成功状态:您已收到预期的响应。
错误状态:执行异步任务时可能会发生一些错误
这些是应用程序执行异步任务时的主要状态。因此,StateMixin 可以帮助你根据这些状态和状态变化来更新 UI。
您只需使用with
关键字将 StateMixin 添加到控制器即可。您还应该指定 StateMixin 要处理的状态类型,例如StateMixin<List<Product>>
。
class ProductController extends GetxController with StateMixin<List<Product>> {}
并且RxStatus
该类还提供了与 StateMixin 一起使用的定义状态。
RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('error message');
StateMixin 提供了Change()
方法,它会根据异步任务的响应来更改状态。你只需要传递新的状态和状态值即可。
change(newState, status: RxStatus.success());
让我们举个例子。
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());
}
}
}
如你所见,在收到包含数据的成功响应后,我通过将响应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),
)
);
}
}
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