当前位置: 首页 > news >正文

Flutter笔记:GetX模块中不使用 Get.put 怎么办

Flutter笔记
GetX模块中不使用 Get.put 怎么办

作者李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/134006728



1. 概述

2. 关于依赖注入

依赖注入(Dependency Injection,DI)是一种编程模式,它旨在管理和注入类之间的依赖关系,以提高代码的可维护性、可测试性和可扩展性。

在 Dart 语言中,依赖注入可以通过不同的方式实现。下面大概看一下一些常见的实现依赖注入的方式。

1. 手写依赖注入

手写依赖注入的有以下三个步骤:

  1. 创建依赖项类:首先创建依赖项的类,这些类包括服务、存储库或其他应用程序组件。
  2. 创建依赖关系:在应用程序中创建依赖项之间的关系,这可以通过构造函数参数或依赖项属性来实现。
  3. 注入依赖项:将依赖项注入到需要它们的类中,通常在构造函数中进行注入。

比如:

// 步骤 1:创建依赖项类
class DataService {String fetchData() {return "Data from DataService";}
}class Logger {void log(String message) {print(message);}
}class MyService {final DataService dataService;final Logger logger;// 步骤 2:创建依赖关系MyService(this.dataService, this.logger);void doSomething() {String data = dataService.fetchData();logger.log(data);}
}void main() {// 步骤 3:注入依赖项final dataService = DataService();final logger = Logger();final myService = MyService(dataService, logger);myService.doSomething();
}

这个例子中,MyService 类依赖于 DataServiceLogger 类,这两个依赖项被通过构造函数注入到 MyService 中。对于大型应用程序,可能需要考虑使用依赖注入容器或注解处理器来更方便地管理依赖项。下面两个小节继续介绍。

2. 使用依赖注入容器

依赖注入容器是管理和注入依赖项的工具,它们可以简化依赖管理过程并提供更高级的功能。在 Dart 中,一些流行的依赖注入容器包括 get_itinjectorkiwi 等。

使用 get_it 的示例:
import 'package:get_it/get_it.dart';class DataService {String fetchData() {return "Data from DataService";}
}class MyService {final DataService dataService;MyService(this.dataService);void doSomething() {String data = dataService.fetchData();print(data);}
}void main() {final getIt = GetIt.instance;getIt.registerSingleton<DataService>(DataService());getIt.registerFactory<MyService>(() => MyService(getIt<DataService>()));final myService = getIt<MyService>();myService.doSomething();
}

在上述示例中,使用 get_it 容器注册并获取依赖项。 get_it 允许您注册单例和工厂方法来创建依赖项,并且能够在整个应用程序中轻松访问这些依赖项。

3. 注解处理器和代码生成

另一种方式是使用注解处理器和代码生成工具,如 injectget_it 的 Generator,来自动生成依赖注入代码。这些工具可以根据您的类和注解自动生成依赖注入的代码,减少手动编写依赖注入的工作。

// 使用 inject 注解
import 'package:inject/inject.dart';
class MyModule {DataService provideDataService() => DataService();
}class DataService {String fetchData() {return "Data from DataService";}
}class MyService {final DataService dataService;MyService(this.dataService);void doSomething() {String data = dataService.fetchData();print(data);}
}void main() {final injector = Injector<MyModule>().injector;final myService = injector.get<MyService>();myService.doSomething();
}

在上述示例中,使用了 inject 注解处理器来生成依赖注入代码,简化了依赖项的注册和获取。

无论您选择手动注入、依赖注入容器还是注解处理器,依赖注入都有助于将应用程序的组件解耦,提高代码的可测试性和可维护性。这种模式在构建大型、复杂的应用程序时特别有用,使代码更易于扩展和维护。

3. 什么是 Get.put

Get.put 是 GetX 状态管理库中的一个方法,它用于将一个控制器(Controller)实例放入 GetX 的依赖注入容器中,使得该控制器可以在整个应用程序中被共享和访问。

  1. 获取依赖: Get.put 的主要目的是将一个控制器实例添加到 GetX 的依赖注入系统中。这可以让您的控制器在整个应用程序中被轻松访问和共享。

  2. 依赖注入: GetX 使用依赖注入来管理应用程序的状态。依赖注入是一种设计模式,它有助于管理对象之间的依赖关系。在这种情况下,Get.put 用于将一个控制器添加到应用程序的依赖项容器中,以便其他部分可以访问它。

  3. 单例模式: 默认情况下,Get.put 创建的控制器是单例的。这意味着无论应用程序的哪个部分使用 Get.find 或其他方法获取该控制器,都将获得同一个实例。这对于共享应用程序状态和逻辑非常有用。

使用示例:

class MyController extends GetxController {var count = 0.obs;
}// 在应用程序的某个地方将 MyController 放入依赖注入容器中
Get.put(MyController());// 在其他部分可以轻松获取 MyController 实例
MyController myController = Get.find<MyController>();// 使用 MyController 实例
myController.count.value = 42;

总之,Get.put 允许您在整个应用程序中访问和共享控制器,是 GetX 库的关键部分,用于实现轻量级的状态管理和依赖注入。

4. 有时候我还真的不喜欢过多使用Get.put

从简单状态管理说起

GetX 模块中提供了太多的解决方案,其中甚至包括 StatefulWidget 的替代方案。GetX 模块官方文档中就直接说,通过 简单状态管理, 你 不再需要 StatefulWidget。比如,经典的几乎在每一个响应式框架都喜欢给出的计数器例子:

// your/path/count_controller.dartclass Controller extends GetxController {int counter = 0;void increment() {counter++;update(); // 当调用增量时,使用update()来更新用户界面上的计数器变量。}
}
import 'your/path/count_controller.dart'// ...其它代码GetBuilder<Controller>(init: Controller(), // 首次启动builder: (_) => Text('${_.counter}',),
)

这个例子中,使用的就是GetX提供的所谓 简单状态管理 的方式。它的状态保存在 Controller 类中,然后在需要用到的地方使 GetBuilder进行包装。

Get.put 和 Get.find

但是——考虑下面一个问题:

你此定义的 Controller 是一个全局状态,它可能不是在一个类、甚至一个文件中的代码中需要使用。那么,你会每次都创建 Controller 类的实例吗?显然这就不能共享数据状态了。

怎么办呢?对于全局共享的数据,很多情况下我们都是使用 Get.putGet.find 来实现的,它们是 GetX 框架提供了一种方便的方式来管理应用程序状态和访问依赖项。

Get.put函数

Get.put 函数用于将一个对象注册为单例,以便在整个应用程序中重用。它通常用于注册 控制器、服务、数据存储类 等全局性的依赖项,使它们可以在整个应用程序的生命周期内被访问。

使用Get.put时,您需要提供一个对象的实例。通常,这将是一个控制器类的实例。比如,下面的例子展示了如何在GetX中使用Get.put来注册和访问一个控制器:

// 1. 创建一个控制器类
class MyController extends GetxController {// 控制器的逻辑和状态
}// 2. 在应用程序初始化时使用Get.put注册控制器
void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {// 注册MyController控制器为单例Get.put(MyController());return MaterialApp(home: Scaffold(body: Center(child: ElevatedButton(onPressed: () {// 3. 在应用程序的任何地方使用Get.find获取控制器实例final myController = Get.find<MyController>();// 使用myController来访问控制器的逻辑和状态},child: Text('Get Controller'),),),),);}
}

Get.find函数

`Get.find 函数用于查找和获取已经注册的单例对象(通常是控制器)的实例。它用于在应用程序的任何地方访问注册的对象,而无需手动传递它们。

使用Get.find时,需要提供对象的类型,以获取已注册对象的实例。可以在应用程序的任何部分使用Get.find来获取已注册对象的实例,而无需显式传递它们。例如

// 获取已注册的MyController对象实例
final myController = Get.find<MyController>();// 使用myController来访问控制器的逻辑和状态

使用 GetxController.find创建单例

依据GetX官方的介绍,如果你需要在许多其他地方使用你的控制器,并且在GetBuilder之外,只需在你的控制器中创建一个get,就可以轻松地拥有它。(或者使用Get.find()) 例如:

class Controller extends GetxController {/// 你不需要这个,我推荐使用它只是为了方便语法。/// 用静态方法:Controller.to.increment()。/// 没有静态方法的情况下:Get.find<Controller>().increment();/// 使用这两种语法在性能上没有区别,也没有任何副作用。一个不需要类型,另一个IDE会自动完成。static Controller get to => Get.find(); // 添加这一行int counter = 0;void increment() {counter++;update();}
}

于是,你可以直接访问你的控制器:

FloatingActionButton(onPressed: () {Controller.to.increment(),} child: Text("${Controller.to.counter}"),
),

哦,看起来似乎“贼简单”,不过接下来就是报错:

错误信息提示你,你需要先使用 Get.put 添加作为依赖添加给GetX框架管理。

—— 对的,我们使用的依然是 Get.find(),还需要见Get.put(); 一下。于是你很不情愿地又在 mian 的一大堆代码中添加了一个导入,创建了一个新的控制器实例,并添加了一条依赖注入。

替代StatefulWidget

既然简单状态管理在很多场景下用于替代StatelessWidget,而一旦遇到想考虑拆分组件避免一个组件写的过大时,就可能遇到简单状态需要在多个拆分后的组件中局部进行共享的问题。

由于,毕竟从需求上来说,这些状态还真的没有其它需要用到的地方了,如果都像 GetService一样去注册,写在 GetMaterialApp 中注册的就会特别多。

一般为了方便查找,我考虑写一个 app/injections.dart 文件,同意管理依赖注入项目,比如:

import 'package:get/get.dart';import '../xxx.dart';class DependencyInjection {static void init() {Get.put<GetConnect>(GetConnect());Get.put<GetProvider>(GetProvider());Get.put<GetProvider>(GetProvider());Get.put(AuthService(GetProvider()));Get.put(RecommendationController());Get.put(CartController());}
}

而在 mian.dart 的应用组件中(如“Myapp”),可以实现一个初始化方法,在这里和其它需要初始化的项目一起完成依赖初始化:

class Myapp extends StatelessWidget {const Myapp({super.key});Future<void> initialization(BuildContext context) async {// ... 其它需要初始化的内容DependencyInjection.init(); // 初始化依赖注入}
}

虽然这已经可以使得代码显得更加整洁清晰。但是,对于一些真的仅仅就是部分代码中共享的状态,我还是不想在 app/injections.dart 注册,我希望仅仅在这些代码中调用的地方才创建实例而不是在应用一启动就有GetX管理单例。

不仅是减少没必要的实例创建,同时我页不用大范围的找文件,尤其是项目变大的时候。那么如果不依赖注入,还有什么办法呢。请看下节。

5. 手动使用单例

简介

这个办法就是在控制器类上做一些手脚,保证外部访问的都是同一实例——实际上使用GetX的Get.put方法时,内部管理的也不就是我们注册的单例。

对于很多真的就是简单的局部共享状态的场景,自己实现单例我个人感觉反而更好。首先,你不需要集中于创建代码初期就从各个模块中导入你的各个控制器,也不需要预先在应用初始化时就创建它们的实例,从而将实例添加到GetX依赖中进行管理。这使得mian文件中的代码更加简洁。如果某个局部状态控制器被移除,你也不需要回到mian文件中来对代码进行改动,只需要删除不用的部分。其次,在Dart语言中,为面向对象的单例实现提供了很方便的支持,仅仅三个小步骤就可以实现严格管理单例。接下来就我们看一下具体该怎么搞。

实现过程

为控制器实现单例可以按照下面的三个步骤进行:

  1. 供一个私有静态属性用于存储唯一的控制器实例;
  2. 创建用于内部静态构造的构造器,尽量避免提供外部可访问的构造方法;
  3. 提供一个外部访问的访问器接口,在该接口中:
  • 如果还没有创建过控制器,则内部构建数以该类的唯一构造器实例后返回;
  • 如果存储的构造器已经非空,则返回该之前创建过的属于该类的唯一构造器实例。

具体案例

基于以上步骤,一个计数器控制器增加单例控制的面向对象实现如下:

import 'package:get/get.dart';/// 计数器控制器类
class CounterController extends GetxController {// 提供一个私有静态属性用于存储唯一的控制器实例static CounterController? _instance;// 仅提供一个私有构造器防止外部创建实例CounterController._();// 提供一个外部访问的访问器接口static CounterController? get to {// 表示仅仅当 _instance 为 null 时,内部构造该控制器实例_instance ??= CounterController._();return _instance;}// 下面表示一些状态变量个状态相关的内容...int counter = 0;void increment() {counter++;update();}
}

接着,就可以在完全不通过 Get.put函数和Get.get函数情况下,改用 CounterController.to 访问器直接使用单例了。

相关文章:

Flutter笔记:GetX模块中不使用 Get.put 怎么办

Flutter笔记 GetX模块中不使用 Get.put 怎么办 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/13400672…...

2023前端面试整理

1. 介绍一下最近参与的项目,负责那些业务,在开发过程中遇到过问题吗&#xff1f;最后是咋样处理的&#xff1f; 之前负责过大小十几个项目&#xff0c;负责过浙里办的整套上架流程&#xff0c;负责过数据大屏统计&#xff0c;后台管理系统文书生成表单生成等&#xff0c;浙政钉…...

文化融合:TikTok如何弥合跨文化差异

随着全球化的加速和数字媒体的崛起&#xff0c;社交媒体平台已经成为连接世界各地人们的纽带。其中&#xff0c;TikTok作为一个引领者&#xff0c;正在以惊人的速度消除跨文化差异&#xff0c;促进文化融合&#xff0c;使人们更加了解和尊重不同背景和传统。 本文将深入探讨Ti…...

asp.net core获取config和env

配置文件的读取和使用 //读取配置文件直接使用 var configModel configuration.GetSection("DataBaseConfig").Get<DataBaseConfigModel>(); //读取配置文件注入到IOC中 services.Configure<AssemblyConfig>(configuration.GetSection("AssemblyC…...

Git不常用命令(持续更新)

今日鸡汤&#xff1a;当你最满足的时候&#xff0c;通常也最孤独&#xff1b;当你最愤慨的时候&#xff0c;通常也最可怜。 此博文会列出一些平时不常用&#xff0c;但是能提高效率的git命令&#xff0c;后续会出IDEA对应的操作步骤 快看看你是不是都用过... 分支&#xff08;…...

PostPreSql 数据库的一些用法

1、varchar 类型转换成数字 select sum(CAST(order_num AS NUMERIC)) from ads_port_cli_cons_freq_rpt where yr2023 and mon 08...

小工具推荐:FastGithub的下载及使用

前言&#xff1a;FastGithub是基于dotnet开发的一款开源Github加速器&#xff0c;通过自动获取与GitHub相关的IP地址并更新本地hosts文件来提高资源访问速度&#xff0c;使GitHub的访问畅通无阻。原理&#xff08;复制过来的&#xff09;&#xff1a; ①修改本机的DNS服务指向…...

硬件信息查看工具 EtreCheckpro mac中文版功能介绍

etrecheckpro mac中文版是一款专业的硬件信息查看工具&#xff0c;它能够快速的检测Mac电脑的软硬件信息&#xff0c;加强用户对自己计算机的了解&#xff0c;EtreCheckPro for Mac下载首先会对电脑的软硬件信息进行扫描收集&#xff0c;之后才会显示出来。EtreCheck Mac版报告…...

宝塔Python3.7安装模块报错ModuleNotFoundError: No module named ‘Crypto‘解决办法

前言 今晚遇到一个问题&#xff0c;宝塔服务器上安装脚本的模块时&#xff0c;出现以下报错&#xff0c;这里找到了解决办法 Traceback (most recent call last):File "/www/wwwroot/unifysign/fuck_chaoxing/fuck_xxt.py", line 4, in <module>from Crypto.…...

优化改进YOLOv5算法:加入ODConv+ConvNeXt提升小目标检测能力——(超详细)

为了提升无人机视角下目标检测效果,基于YOLOv5算法,在YOLOv5主干中实现了Omnidimensional Convolution(ODConv),以在不增加网络宽度和深度的情况下提高精度,还在YOLOv5骨干网中用ConvNeXt块替换了原始的C3块,以加快检测速度。 1 Omni-dimensional dynamic convolution …...

ElasticSearch安装、插件介绍及Kibana的安装与使用详解

ElasticSearch安装、插件介绍及Kibana的安装与使用详解 1.安装 ElasticSearch 1.1 安装 JDK 环境 因为 ElasticSearch 是用 Java 语言编写的&#xff0c;所以必须安装 JDK 的环境&#xff0c;并且是 JDK 1.8 以上&#xff0c;具体操作步骤自行百度 安装完成查看 java 版本 …...

JVM | 命令行诊断与调优 jhsdb jmap jstat jps

目录 jmap 查看堆使用情况 查看类列表&#xff0c;包含实例数、占用内存大小 生成jvm的堆转储快照dump文件 jstat 查看gc的信息&#xff0c;查看gc的次数&#xff0c;及时间 查看VM内存中三代&#xff08;young/old/perm&#xff09;对象的使用和占用大小 查看元数据空…...

SQL 表达式

SQL 表达式 表达式是计算值的一个或多个值、运算符和SQL函数的组合。这些SQL表达式类似于公式&#xff0c;它们是用查询语言编写的。 您还可以使用它们查询数据库中的特定数据集。 句法 考虑SELECT语句的基本语法&#xff0c;如下所示&#xff1a; SELECT column1, column2, …...

Unity3D 打包发布时生成文件到打包目录

有时候需要自己创建批处理文件或日志文件&#xff0c;在启动程序的同级目录使用&#xff0c;减少手动操作的时间和错误率。主要使用到的是OnPostprocessBuild方法。 1、在工程中的Editor文件夹下创建脚本 2、将文件放入Plugins的相关目录 3.脚本内容 using System.Collection…...

Elasticsearch中使用join来进行父子关联

在使用关系数据库进行开发的过程中&#xff0c;你可能会经常使用外键来表示父表和子表之间的关联关系&#xff0c;在Elasticsearch中&#xff0c;有哪些方法可以用来让开发者解决索引之间一对多和多对多的关联关系的问题呢 1 使用对象数组存在的问题 你可以很方便地把一个对象…...

提供一个springboot使用h2数据库是无法使用脚本并报错的处理方案

环境描述 springboot 2.6.2 mybatis-plus-boot-starter 3.5.1 mysql-connector-java 8.0.11 查阅了很多博客&#xff0c;说是使用spring.datasource.schema或者spring.sql.init.schema-locations指定脚本也均无效。不使用启动脚本&#xff0c;启动后在h2控制台&#xff…...

【组合计数】CF1866 H

Problem - H - Codeforces 题意 思路 不知道这种trick叫什么&#xff0c;昨天VP刚遇到过 设 f[x] 为恰好有一个最大值为 x 的方案数&#xff0c;我们要求这个&#xff0c;那就设 g[x] 为 至少有一个最大值为 x 的方案数&#xff0c;那么答案就是 f[x] g[x] - g[x - 1] 这里…...

JavaSpringbootmysql农产品销售管理系统47627-计算机毕业设计项目选题推荐(附源码)

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设农产品销售管理系统。…...

一文5000字从0到1使用Jmeter实现轻量级的接口自动化测试(图文并茂)

接口测试虽然作为版本的一环&#xff0c;但是也是有一套完整的体系&#xff0c;有接口的功能测试、性能测试、安全测试&#xff1b;同时&#xff0c;由于接口的特性&#xff0c;接口的自动化低成本高收益的&#xff0c;使用一些开源工具或一些轻量级的方法&#xff0c;在测试用…...

蓝桥杯每日一题0223.10.23

第几天 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 简单枚举&#xff08;用k来记录经过的天数&#xff09; #include<bits/stdc.h> using namespace std; bool is_ren(int n) {if(n % 400 0 || (n % 4 0 && n % 100 ! 0))return true;return false; } int …...

php危险函数及rce漏洞

php代码执行语句 eval() eval()语句 eval() 会将符合PHP 语法规范字符串当作php 代码执行。 <meta charset"UTF-8"> <pre><?php$dd$_REQUEST[dd];eval($dd);?>可以执行php代码 也可以套一层system执行系统操作指令 assert()函数 assert() …...

4. 寻找两个正序数组的中位数

1. 题目 见 寻找两个正序数组的中位数 2. 解题思路 首先一看到题目说是正序数组&#xff0c;且时间复杂度要求在对数级别&#xff0c;所以自然想到了双指针中的二分法。 首先来看一下&#xff0c;假设输入是这两个数组&#xff0c;那么将其逻辑合并成一个大数组的话&#x…...

Stable Diffusion AI绘图

提示词&#xff1a; masterpiece, best quality, 1girl, (anime), (manga), (2D), half body, perfect eyes, both eyes are the same, Global illumination, soft light, dream light, digital painting, extremely detailed CGI anime, hd, 2k, 4k background 反向提示词&…...

MR混合现实情景实训教学系统在旅游管理专业中的应用

在旅游管理专业中&#xff0c;MR混合现实情景实训教学系统的主要应用包括但不限于以下几个方面&#xff1a; 1. 实地考察的替代&#xff1a;对于一些无法实地考察的景点或设施&#xff0c;学生可以通过MR系统进行虚拟参观&#xff0c;从而了解其实际情况。这不仅可以减少时间和…...

CentOS 使用线程库Pthread 库

1、Pthread 库说明 pthread 库是Linux系统默认线程库。 在Linux 系统环境中&#xff0c;编辑C/C程序使用pthread 库&#xff0c;需要添加对应的头文件&#xff0c;并链接pthread库。 #include<pthread.h> 2、Pthread 库核心方法 pthread_create 函数定义&#xff1…...

#力扣:LCP 01. 猜数字@FDDLC

LCP 01. 猜数字 - 力扣&#xff08;LeetCode&#xff09; 一、Java class Solution {public int game(int[] guess, int[] answer) {int cnt0;for(int i0;i<3;i){if(guess[i]answer[i])cnt;}return cnt;} }...

kafka丢数据的原因

目录 背景kafkaClient代码消息丢失的可能原因broker is downRD_KAFKA_MSG_SIZE_TOO_LARGE分区问题Kafka Broker的处理能力无法跟上&#xff0c;可能会出现以下情况 Some基础知识补充 背景 采用的client是librdkafka&#xff0c;在producerClient Send的数据时候发现会有数据丢…...

音视频编解码技术学习笔记

音视频编解码技术是音视频处理领域的重要部分&#xff0c;涉及到对原始音视频数据的压缩、编码和解码。以下是音视频编解码技术的一些要点和难点&#xff1a; 要点&#xff1a; 压缩技术 音视频编解码的核心是对原始音视频数据进行压缩&#xff0c;以减小文件大小和传输带宽…...

[C#基础训练]FoodRobot食品管理部分代码-1

代码参考: using System;namespace FoodRobotDemo { public class FoodRobot{private int[] foodCountArr;private string[] foodNameArr;public FoodRobot(){foodCountArr new int[3];foodNameArr new string[3] {"航天","航空","宇航" };}…...

YModem协议总结

《YModem协议总结》 目录 第1章 YModem协议简介 4 1.1 基本介绍 4 1.2 YModem基本介绍 4 第2章 YModem传输协议 5 2.1 起始帧的数据格式 5 2.2 数据帧的数据格式 5 2.3 结束帧数据结构 6 2.4 文件传输过程 6 2.5 CRC的计算 7 附录A 附录 8 A.1 附录 8 第1章 YModem协议简…...