Flutter Getx 状态管理

状态管理

目前,Flutter有几种状态管理器。但是,它们中的大多数都涉及到使用ChangeNotifier来更新widget,这对于中大型应用的性能来说是一个很糟糕的方法。你可以在Flutter的官方文档中查看到,ChangeNotifier应该使用1个或最多2个监听器,这使得它们实际上无法用于任何中等或大型应用。

Get 并不是比任何其他状态管理器更好或更差,而是说你应该分析这些要点以及下面的要点来选择只用Get,还是与其他状态管理器结合使用。

Get不是其他状态管理器的敌人,因为Get是一个微框架,而不仅仅是一个状态管理器,既可以单独使用,也可以与其他状态管理器结合使用。

Get有两个不同的状态管理器:响应式状态管理器、简单的状态管理器。

响应式状态管理器

  1. 响应式编程可能会让很多人感到陌生,因为它很复杂,但是GetX将响应式编程变得非常简单。
    • 你不需要创建StreamControllers.
    • 你不需要为每个变量创建一个StreamBuilder。
    • 你不需要为每个状态创建一个类。
    • 你不需要为一个初始值创建一个get。
  2. 使用 Get 的响应式编程就像使用 setState 一样简单。
  3. 让我们想象一下,你有一个名称变量,并且希望每次你改变它时,所有使用它的小组件都会自动刷新。

响应式状态管理器-计数器

让我们想象一下,你有一个名称变量,并且希望每次你改变它时,所有使用它的小组件都会自动刷新。

这就是你的计数变量。

int _counter = 0;

要想让它变得可观察,你只需要在它的末尾加上".obs"。

RxInt _counter = 0.obs;

而在UI中,当你想显示该值并在值变化时更新页面,只需这样做。

Obx(() => Text("$_counter"));

这就是全部,就这么简单。

import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  RxInt _counter = 0.obs;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Gex 计数器"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Obx(() => Text("$_counter"))
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          _counter++;
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

声明一个响应式变量三种方式

第一种 使用 Rx{Type}

final name = RxString('');
final isLogged = RxBool(false);
final count = RxInt(0);
final balance = RxDouble(0.0);
final items = RxList<String>([]);
final myMap = RxMap<String, int>({});

第二种是使用 Rx,规定泛型 Rx。

final name = Rx<String>('');
final isLogged = Rx<Bool>(false);
final count = Rx<Int>(0);
final balance = Rx<Double>(0.0);
final number = Rx<Num>(0)
final items = Rx<List<String>>([]);
final myMap = Rx<Map<String, int>>({});
// 自定义类 - 可以是任何类
final user = Rx<User>();

第三种 更实用、更简单、更可取的方法,只需添加 .obs 作为value的属性。(推荐)

final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;
// 自定义类 - 可以是任何类
final user = User().obs;

监听自定义类数据的变化

第一步:应用程序入口设置

import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: "GetX",
      home: MyHomePage(),
    );
  }
}

第二步:创建Person 类

import 'package:get/get.dart';
class Person {
  // rx 变量
  RxString name = "Jimi".obs;
  RxInt age = 18.obs;
}

第三步:获取类属性值以及改变值

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import './person.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  var person = Person();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Getx Obx"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Obx(() => Text(
              "我的名字是 ${person.name.value}",
              style: const TextStyle(color: Colors.red, fontSize: 30),
            ))
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          person.name.value = person.name.value.toUpperCase();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Flutter Getx 简单的状态管理(依赖管理)GetxController

Getx 依赖管理简介

Get有一个简单而强大的依赖管理器,它允许你只用1行代码就能检索到与你的Bloc或Controller相同的类,无需Provider context,无需inheritedWidget。

Controller controller = Get.put(Controller());
// 而不是 Controller controller = Controller();

想象一下,你已经浏览了无数条路由,现在你需要拿到一个被遗留在控制器中的数据,那你需要一个状态管理器与Provider或Get_it一起使用来拿到它,对吗?用Get则不然,Get会自动为你的控制器找到你想要的数据,而你甚至不需要任何额外的依赖关系。

Controller controller = Get.find();
//是的,它看起来像魔术,Get会找到你的控制器,并将其提供给你。你可以实例化100万个控制器,Get总会给你正确的控制器。

多页面之间的数据共享

  1. Flutter默认创建的 "计数器 "项目有100多行(含注释),为了展示Get的强大功能,我将使用 GetX 重写一个"计数器 Plus版",实现:
    • 每次点击都能改变状态
    • 在不同页面之间切换
    • 在不同页面之间共享状态
    • 将业务逻辑与界面分离

第一步:应用程序入口设置

import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      ....
    );
  }
}

第二步:新建CountController

import 'package:get/get.dart';
class CountController extends GetxController{
  var count = 0.obs;
  void inc(){
    count++;
    update();
  }
  void dec(){
    count--;
    update();
  }
}

第三步:Home.dart执行inc方法

import 'package:flutter/material.dart';
import '../../controller/count.dart';
import 'package:get/get.dart';
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
  CountController countController = Get.put(CountController());
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Obx(()=>Text("${countController.count}",style:
                       Theme.of(context).textTheme.headline1)),
          ElevatedButton(onPressed: (){
            countController.inc();
          }, child: const Text("数值+1"))
        ],
      ),
    );
  }
}

第四步:Category.dart执行dec方法

你可以让Get找到一个正在被其他页面使用的Controller,并将它返回给你。

final countController= Get.find<CountController>();
// 或者
final CountController countController = Get.find();
import 'package:flutter/material.dart';
import '../../controller/count.dart';
import 'package:get/get.dart';
class CategoryPage extends StatefulWidget {
  const CategoryPage({super.key});
  @override
  State<CategoryPage> createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
  final CountController countController = Get.find();
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Obx(() => Text("${countController.count}",
                         style: Theme.of(context).textTheme.headline1)),
          ElevatedButton(
            onPressed: () {
              countController.dec();
            },
            child: const Text("数值-1"))
        ],
      ),
    );
  }
}

GetxController 绑定数据的几种方法

方法1:

CountController countController = Get.put(CountController());
// 或者
final CountController countController = Get.find();
Obx(()=>Text("${countController.count}",style:
Theme.of(context).textTheme.headline1)),

方法2:

只是绑定数据无需调用Get.put(CountController());

GetX<CountController>(
  init: CountController(),
  builder: (controller) {
    return Text(
      "${controller.count}",
      style: const TextStyle(color: Colors.green, fontSize: 30),
    );
  },
),

方法3:

CountController countController = Get.put(CountController());
或者
final CountController countController = Get.find();
GetBuilder<CountController>(
  init: countController,
  builder: (controller) {
    return Text(
      "${controller.count}",
      style: const TextStyle(color: Colors.green, fontSize: 30),
    );
  },
)

results matching ""

    No results matching ""