GetX-响应式状态管理(被动)

官网地址:https://pub.flutter-io.cn/packages/get

关于状态管理,目前主流有四个: GetX,BLoC、MobX、Provider。
BLoC 非常安全和高效,但是非常复杂,理解与运用不适合初学者。
MobX 比 BLoC 更容易,而且是响应式的,但是需要使用一个代码生成器,需要时间等待,对开发效率有影响。
BloC(全局管理,event,形式类似mvvm):

  1. widget 触发event 事件
  2. bloc 接收event 事件并作出逻辑处理
    3.并把逻辑处理结果给返回出来
  3. UI展示数据
    所以,目前市场最常见的是Provider和GetX。
    但是,目前在pub上来看,GetX可能更受青睐。


    get.png
provider.png

相对于provide ,我觉得GetX更有优势的地方在于:GetX 不需要上下文,突破了InheritedWidget的限制,我们可以在全局和模块间共享状态,而Provider 在遇到非父子组件的状态管理问题,需要借助别的手段(eventbus,全局,单例)。
针对context做个简单的对比:provide中路由需要对 context 的依赖。

///原始
Navigator.push(context, MaterialPageRoute(
      builder: (BuildContext context) {
        return NextScreen();
      },
    ));
///provider封装后
Navigator.pushNamed(context, RouteName.nextName);
///返回
Navigator.pop(context);
///GetX
Get.to(NextScreen())
///返回
Get.back();
///打开新页面,并且用新页面替换旧页面(删除旧页面)
Get.off(NextScreen());
///打开新页面并删除之前的所有路由
Get.offAll(NextScreen());
///导航到新页面,在返回时接收返回数据
var data = await Get.to(NextScreen());
///带返回值返回前一个路由,配合上面使用
Get.back(result: 'success');

通过Snackbar的使用来感受下getx

安装

dependencies:
  get: 

引入

import 'package:get/get.dart';

Snackbar使用
导入依赖后,在应用程序顶层把GetMaterialApp 作为顶层,然后通过Get.snackbar() 来显示 snackbar

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: Scaffold(
        appBar: AppBar(
          title: Text("GetX Title"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () {
                  Get.snackbar("Snackbar 标题", "欢迎使用Snackbar");
                },
                child: Text("显示 Snackbar"))
            ],
          ),
        ),
      ),
    );
  }
}

效果图


Simulator Screen Shot - iPhone 8 - 2022-03-24 at 11.33.11.png
将
Get.snackbar("Snackbar 标题", "欢迎使用Snackbar");
替换成下方代码
Scaffold.of(context).showSnackBar(
       SnackBar(
            content: Text('Have a snack!'),
        ),
);

运行下会报一个错误

///报错原因是 : 在Scaffold子组件里的build方法可以才可以调用Scaffold.of方法
Scaffold.of() called with a context that does not contain a Scaffold.

上门这个错误有很多解决办法,例如抽离出一个子控件,使用GlobalKey存储ScaffoldState ,但是无疑都会增加代码量。

谈一下被动状态管理

被动状体管理 :通俗的讲就是当你改变一个值,相关小控件随之变化。
现有项目中我通常是采用mvvm加provider的方式,现在看下getx的实现

class ObxCountExample extends StatelessWidget {

  ///声明Rx变量以及改变计数器的方法
 //StringX  RxString
 //IntX RxInt
 //MapX RxMap
 //列表X  RxList
 //NumX RxNum
 //DoubleX  RxDouble
  RxInt count = RxInt(0);
  void increment() {
    count++;
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          ///使用Obx监听值的改变
          Obx(() => Text(
            "count的值为: $count",
            style: TextStyle(color: Colors.red, fontSize: 30),
          )),
          SizedBox(height: 20,),
          ElevatedButton(
              onPressed: () {
                increment();
              },
              child: Text("点我加1"))
        ],
      ),
    );
  }
}
Simulator Screen Shot - iPhone 8 - 2022-03-24 at 11.57.51.png

如果是一个类里的值发生改变

class Programmer {
  // rx 变量
  var name = "mabo".obs;
  var age = 30.obs;
}

class ObxCustomClassExample extends StatelessWidget {

  var programmer = Programmer();
  
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Obx(() => Text(
            "我的名字是 ${programmer.name.value}",
            style: TextStyle(color: Colors.red, fontSize: 30),
          )),
          SizedBox(height: 20,),
          ElevatedButton(
              onPressed: () {
                programmer.name.value = programmer.name.value.toUpperCase();
              },
              child: Text("转换为大写"))
        ],
      ),
    );
  }
}

上述 .obs 和 Rx([]) ,基本等价,都是obs状态管理的创建属性的方式

UI和逻辑分离-GetxController

核心思想:


逻辑.png

定义一个继承GetxController的类: 逻辑- Controller 层
定义一个GetBuilder类:界面- *View 层
controlelr 里面调用update() 刷新UI
首先,定义控制器继承自GetxController(生命周期(onInit()),onReady()),onClose()))

import 'package:get/get.dart';

class Teacher {
  // rx 变量
  var name = "mabo".obs;
  var age = 30.obs;
}

class MyController extends GetxController {

  // 第一种
  // var teacher = Teacher();
  //
  // void convertToUpperCase() {
  //   teacher.name.value = teacher.name.value.toUpperCase();
  // }

  // 第二种
  // var teacher =  Teacher(name: "Jimi", age: 18).obs;
  // void convertToUpperCase() {
  //   teacher.update((val) {
  //     teacher.value.name = teacher.value.name.toString().toUpperCase();
  //   });
  // }

  // 第三种
  var teacher = Teacher();

  void convertToUpperCase() {
    teacher.name.value = teacher.name.value.toUpperCase();
    update();
  }
}

之后,实例化控制器并使用

import 'package:flutter/material.dart';
import 'package:flutter_getx_example/GetXControllerExample/MyController.dart';
import 'package:get/get.dart';

class GetXControllerExample extends StatelessWidget {

  // 第一种
 // MyController myController = Get.put(MyController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("GetX Obx---GetXController"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            // 第一种
            // Obx(() => Text(
            //   "我的名字是 ${myController.teacher.name}",
            //   style: TextStyle(color: Colors.red, fontSize: 30),
            // )),
            // 第二种
            // GetX(
            //   init: MyController(),
            //   builder: (controller) {
            //     return Text(
            //       "我的名字是 ${controller.teacher.name}",
            //       style: TextStyle(color: Colors.green, fontSize: 30),
            //     );
            //   },
            // ),
            // 第三种
            GetBuilder(
              init: myController,
              builder: (controller) {
                return Text(
                  "我的名字是 ${controller.teacher.name}",
                  style: TextStyle(color: Colors.green, fontSize: 30),
                );
              },
            ),
            SizedBox(height: 20,),
            ElevatedButton(
              onPressed: () {
                // 第一种
                myController.convertToUpperCase();

                // 第二种
                // Get.find().convertToUpperCase();

              },
              child: Text("转换为大写"))
          ],
        ),
      ),
    );
  }
}

实现效果


Simulator Screen Shot - iPhone 8 - 2022-03-24 at 13.43.55.png

GetxController UniqueID

开发的过程中会碰到一种情况,就是多个地方引用了同一个属性,但我只想单独更新某一个地方,那么就可以用UniqueID来进行区分。
首先,定义控制器继承自GetxController,并且定义uniqueID

import 'package:get/get.dart';

class CountController extends GetxController {
  var count = 0;

  void increment() {
    count++;
    update(['jimi_count']);
  }
}

class GetXControllerUniqueIDExample extends StatelessWidget {

 CountController countController = Get.put(CountController());

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text("GetX Obx---GetXController"),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         crossAxisAlignment: CrossAxisAlignment.center,
         children: [
           GetBuilder(
             builder: (controller) {
               return Text(
                 "计数器值为: ${controller.count}",
                 style: TextStyle(color: Colors.red, fontSize: 30),
               );
             },
           ),
           GetBuilder(
             id: 'jimi_count',
             builder: (controller) {
               return Text(
                 "计数器值为: ${controller.count}",
                 style: TextStyle(color: Colors.green, fontSize: 30),
               );
             },
           ),
           SizedBox(height: 20,),
           ElevatedButton(
             onPressed: () => countController.increment(),
             child: Text("增加"))
         ],
       ),
     ),
   );
 }
}

红色的没有改变,绿色的改变了


截屏2022-03-24 下午1.56.20.png

GetxService

GetView

除了状态管理、路由管理、依赖管理之外,还有网络数据的管理,有待补充。

你可能感兴趣的:(GetX-响应式状态管理(被动))