GetX学习笔记

2023-06-08  本文已影响0人  _破晓之翼

getx状态管理框架学习笔记
在这里学习了:
Flutter应用框架搭建(一)GetX集成及使用详解 - 掘金 (juejin.cn)

一、依赖添加

dependencies:
  get: ^4.6.5

二、初始化

要使用 GetX 需要对 GetX 进行初始化,需将默认的 MaterialApp 替换为

  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

三、状态管理

GetX 提供了两种响应式状态管理的方法:响应式变量方式状态管理器方式

1、响应式变量方式

定义一个响应式变量,只需在变量的末尾加上一个 .obs 就可将变量定义为响应式变量:
var count = 0.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;

获取响应式变量的值

使用的时候调用 value 即可拿到变量的值。

/////////// 注意对于 List 、Map 则不需要加 .value。///////////////

bool isLoggedValue = isLogged.value
int countValue = count.value
double numberValue = number.value
String item = items[0] //不需要.value
int value = myMap['key'] //不需要.value
String name = user.value.name

更新数据:

对于基础数据类型,只需要对 value 重新赋值即可更新数据并通过 Obx 刷新界面:

isLogged.value = true
count.value = 1
number.value = 12.0

对于其他数据类型需要调用 update 或者变量方法更新,如下:

user.update((value) {  
value?.name = "123";
});

或者使用变量名方法重新赋值一个对象,比如变量名为 user 则可使用 user() 方法进行更新:

user(User(name: "abcd", age: 25));

刷新界面

在界面上使用响应式变量只需在使用变量的控件上包裹 Obx 即可实现响应式更新,即变量的值发生变化时自动刷新界面:

Obx(() => Text("${count.value}"))

数据变化监听

除了使用 Obx 实现界面数据自动刷新外,GetX 提供了多种手动方式对响应式变量进行数据变化监听,当数据发生变化时执行自定义的逻辑,比如数据变更后重新请求接口等。

使用方式:

///每次`count`变化时调用。
ever(count, (newValue) => print("$newValue has been changed"));
///只有在变量count在第一次被改变时才会被调用。
once(count, (newValue) => print("$newValue was changed once"));
///防DDos - 每当用户停止输入1秒时调用,例如。
debounce(count, (newValue) => print("debouce$newValue"), time: Duration(seconds: 1));
///忽略1秒内的所有变化,只有最后一次会触发回调。
interval(count, (newValue) => print("interval $newValue"), time: Duration(seconds: 1));

Eg. 计数器例子

class CounterPage extends StatelessWidget {
  var count = 0.obs;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Counter"),
      ),
      body: Center(
        child: Obx(
            () => Text("${count.value}", style: const TextStyle(fontSize: 50))),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () => count++,
      ),
    );
  }
}

2、状态管理器

GetX 还提供了使用 Controller 来管理状态,实现一个自定义 Controller 类继承自 GetxController ,Controller 中进行业务逻辑的处理,当需要改变状态数据时调用 update() 来通知数据改变。本项目在很多地方用到。
拿计数器例子来说。

controller中,使用 Controller 来管理状态,自定义Controller 类继承至GetxController。
class CounterController extends GetxController{
  int count = 0;
  void increment(){
    count ++ ;
    update();
  }
}

view中,使用 GetBuilder 进行包裹,这样使用 Controller 中的数据变化时,调用 update() 后就会刷新界面控件。

GetBuilder<CounterController>(        
    init: CounterController(), //Controller 首次初始化
    builder: (controller) {
        return Text("${controller.count}", style: const TextStyle(fontSize: 50));
})

init: CounterController()只用初始化一次,之后的GetBuilder中不用写init。

Eg.计数器例子

class CounterController extends GetxController {
  int count = 0;

  void increment() {
    count++;
    update();
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Counter"),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            GetBuilder<CounterController>(
                init: CounterController(),

                /// 初始化 Controller
                builder: (controller) {
                  return Text("${controller.count}",
                      style: const TextStyle(fontSize: 50));
                }),
            GetBuilder<CounterController>(

                ///没有进行初始化
                builder: (controller) {
              return Text("${controller.count}",
                  style: const TextStyle(fontSize: 50));
            }),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          ///使用 find 找到 Controller
          CounterController controller = Get.find();

          ///调用 Controller 方法
          controller.increment();
        },
      ),
    );
  }
}

四、依赖

依赖管理。

解释:在GetBuilder 的 init 中初始化Controller 后,可在其他地方使用Get.find() 找到初始化的Controller。这就是依赖管理。
GetX 依赖管理可以注入任意类型的实例,并提供了多种依赖注入方式。

依赖注入

① Get.put

Get.put是 GetX 状态管理库中的一个方法,用于向 GetX 依赖注入系统中注册一个实例。依赖注入,是一种设计模式,它的目的是通过将依赖项注入到对象中来增强应用程序的可测试性、可维护性和可扩展性。
在 GetX 中,可以使用 get.put() 方法向依赖注入系统中注册一个实例。
例如,假设有一个 UserController 类用于管理用户信息,可以在应用程序启动时使用 get.put() 方法将其注册:

Get.put<UserController>(UserController());
Get.put<UserController>(UserController(), permanent: true);
Get.put<UserController>(UserController, tag: "counter");

依赖注入时除了依赖类的实例以外还可以设置额外参数:

在这个示例中,UserController 实例被注册为全局单例,可以在整个应用程序中访问该实例。可以在其他类中使用 Get.find() 方法来获取已注册的实例:

class UserProfilePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 获取 UserController 实例
    final UserController controller = Get.find();
    return Scaffold(
      appBar: AppBar(title: Text('User Profile')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Username: ${controller.username}'),
            Text('Email: ${controller.email}'),
          ],
        ),
      ),
    );
  }
}

② Get.lazyPut()

Get.lazyPut() 是 GetX 状态管理库中的一个方法,它与 Get.put() 类似,也用于向 GetX 依赖注入系统中注册一个实例。不同之处在于,Get.lazyPut() 方法是“延迟注册”,即只有在该实例第一次被引用时才会创建。
这种延迟注册的好处在于,可以避免在应用程序启动时创建不必要的实例,从而提高性能和内存使用效率。例如,如果有一个耗时的初始化过程,可以使用 Get.lazyPut() 方法来延迟创建该实例。
下面是一个示例,展示了如何使用 Get.lazyPut() 方法:

class UserController extends GetxController {
  final UserRepository _repository;
  UserController(this._repository);
  Future<void> init() async {
    // 耗时的初始化过程
  }
}

void main() async {
  // 延迟注册 UserController 实例
  Get.lazyPut<UserController>(() => UserController(UserRepository()));

  runApp(MyApp());

  // 等待 UserController 初始化完成
  await Get.find<UserController>().init();
}

在示例中,UserController 实例通过 Get.lazyPut() 方法进行延迟注册,只有在实例被引用时才会创建。(即第一次 find 某一个类的时候才会进行初始化) 在应用程序启动时,UserController 的初始化过程被异步执行,初始化完成后才继续执行应用程序。
需要注意的是,Get.lazyPut() 方法只会创建一个实例,并且该实例会被缓存。如果你需要每次获取实例时都重新创建一个新的实例,请使用 Get.create() 方法。

lazyPut 同样有额外参数,跟 put 基本相同。

③ Get.putAsync

putAsync 可以异步注册一个实例。用于某些实例需要异步初始化时使用,比如 SharedPreferences:

Get.putAsync<SharedPreferences>(() async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setInt('counter', 12345);
  return prefs;
})

跟 put 一样,同样拥有 permanent 和 tag 参数,且作用一样。

④ Get.create

create 与 put 使用方式上基本类似,不同的是它的 permanent 默认为 true。

Get.create<CounterController>(() => CounterController());

获取实例

可以使用以下方法获取依赖的实例:

final controller = Get.find<CounterController>();
// 或者
CounterController controller = Get.find();
// 通过 tag 获取
final controller = Get.find<CounterController>("counter");

移除实例

也可以通过 delete() 方法来手动移除注入的依赖实例,大部分情况下不需要手动调用该方法,GetX 内部会自动处理,当不需要时自动移除

Get.delete<CounterController>();

五、路由管理

普通路由

Get.to(CounterPage());

使用 arguments 进行参数传递:

Get.to(CounterPage(), arguments: count);

使用 arguments 方式可以传递任意类型的参数。
在下个页面获取参数:

dynamic args = Get.arguments;
Get.off(CounterPage());
Get.offAll(CounterPage());
Get.back();

返回传参:

Get.back(result: 'success');

获取返回参数:

var data = await Get.to(CounterPage());

别名路由

首先,需要创建一个AppRouter 类用于统一配置路由映射关系:
GetPage 定义别名与页面的映射关系。

abstract class AppRouter {
  static final pages = [
    GetPage(
      name: AppPath.login,
      page: () => const LoginPage(),
    ),
    GetPage(
      name: AppPath.register,
      page: () => const RegisterPage(),
    ),
    GetPage(
      name: AppPath.forgetPassword,
      page: () => const ForgetPasswordPage(),
    ),
    GetPage(
      name: AppPath.setProfile,
      page: () => const SetProfilePage(),
    ),
  ];
}

同时也可以创建AppPath 类用于统一配置路由名称

abstract class AppPath {
  static const String home = '/';
  static const String login = '/login';
  static const String register = '/register';
  static const String forgetPassword = '/forgetPassword';
  static const String setProfile = '/setProfile';
  static const String startLive = '/startLive';
  static const String liveRoom = '/liveRoom';
  static const String aboutUs = '/aboutUs';
  static const String editProfile = '/EditProfile';
  static const String setMySignature = '/setMySignature';
  static const String myFollowing = '/myFollowing';
  static const String feedback = '/feedback';
  static const String sessionList = '/sessionList';
}

然后在 GetMaterialApp 进行initialRoute 和 getPages 的配置,即初始页面和路由映射集合:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
        title: 'Flutter Demo',
        initialRoute: AppPath.home,
        getPages: AppRouter.pages, 
        theme: ThemeData(
          primarySwatch: Colors.blue,
        )
    );
  }
}
Get.toNamed(RouteGet.login);
Get.toNamed(RouteGet.login, arguments: {"name":"aaaa"});

也可以直接在路由别名后面跟参数,类似于 Url get 传参的方式:

Get.toNamed("/NextScreen?device=phone&id=354&name=Enzo");
dynamic args = Get.arguments;

使用别名后 Url 传递参数的方式,使用 Get.parameters 获取参数:

Get.parameters['device']

Binding

Bindings 是 GetX 状态管理库中的一个概念,它用于在页面或路由生命周期中注册和注销依赖项,以确保资源的正确释放和管理。
在 GetX 中,每个页面或路由都可以有一个对应的 Binding 类,该类负责管理页面或路由所需要的所有依赖项。当通过 GetX 路由进入页面时,会自动调用 dependencies 方法, 可以在这里进行依赖关系的注册等。

别名路由举例:

class LoginBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => LoginController());
  }
}

然后在GetPage 中进行绑定

GetPage(
  name: AppPath.login,
  page: () => const LoginPage(),
  binding: LoginBinding(),
),

普通路由使用:

Get.to(CounterPage(), binding: CounterBinding());
上一篇 下一篇

猜你喜欢

热点阅读