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<void>(
      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<MyController>(
            //   init: MyController(),
            //   builder: (controller) {
            //     return Text(
            //       "我的名字是 ${controller.teacher.name}",
            //       style: TextStyle(color: Colors.green, fontSize: 30),
            //     );
            //   },
            // ),
            // 第三种
            GetBuilder<MyController>(
              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<MyController>().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<CountController>(
             builder: (controller) {
               return Text(
                 "计数器值为: ${controller.count}",
                 style: TextStyle(color: Colors.red, fontSize: 30),
               );
             },
           ),
           GetBuilder<CountController>(
             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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容