Flutter中GetX的用法(超详细使用指南之路由依赖管理篇)

目录

1.前言

2.GetX 依赖管理概述

1.GetX 依赖管理的基本概念

2.与其他依赖管理工具的比较

3. 基础依赖注入

1.Get.put

2.Get.lazyPut

3.Get.putAsync

4.高级依赖注入

1.使用Get.create

2.依赖生命周期管理

5. 参考资料


1.前言

        今天这篇博客主要介绍Getx的三大功能之一的依赖管理。依赖管理是软件开发中的一个关键部分,尤其是在复杂应用中。它帮助开发者管理应用中的各种依赖,确保依赖的实例化和生命周期管理变得更加简单和高效。

2.GetX 依赖管理概述

1.GetX 依赖管理的基本概念

        GetX 提供了一种简单且高效的依赖注入方式,通过少量代码即可实现依赖的注入、管理和访问。它主要通过Get.put、Get.lazyPut、Get.putAsync和Get.create等方法来实现依赖管理。

2.与其他依赖管理工具的比较

        Provider:Provider 是 Flutter 官方推荐的依赖注入和状态管理工具。它需要较多的样板代码,使用起来相对复杂。
        Riverpod:Riverpod 是 Provider 的增强版,提供了更多的功能和更好的性能,但学习曲线较陡。
        GetX:GetX 简单易用,提供了更多的功能,如路由管理和状态管理,适合各种规模的项目。

3. 基础依赖注入

1.Get.put

        Get.put 是 GetX 提供的一个方法,用于将一个实例注入到依赖管理系统中。它的主要作用是创建一个新的实例,并将其注册为依赖,供整个应用程序的其他部分使用。使用 Get.put 可以方便地管理和访问依赖实例,避免手动管理实例的生命周期。

        它的使用场景如下:

        1.全局单例:需要在整个应用程序中共享的依赖。

        2.初始化即创建:需要在应用启动时立即创建的依赖。

        我们使用Get.put的时候,还可以配置一些选项:

  1. dependency:要注入的依赖实例
  2. tag:依赖实例的可选标签,用于区分相同类型的不同实例。
  3. permanent:是否将依赖设置为永久存在,即使不再使用也不会被销毁。

       我们可以通过一个例子说明Get.put的用法。

        在这个例子中,我们在首页操作计时器,然后在收藏页面调用HomeController中的计时器的点击次数。

图1.Get.put用法

        我们来看看如何实现这个功能。

        1.首先我们创建一个控制器,它包含计数逻辑。

class HomeController extends GetxController {var count = 0.obs;void increment() {count++;}
}

        2.在应用启动时注入依赖

        在 main 方法中使用 Get.put 将 CounterController 注入到依赖管理系统中。

void main() {// 注入依赖Get.put(HomeController());runApp(const MyApp());
}

        3.在页面中使用依赖

        完整代码:

import 'package:flutter/material.dart';
import 'package:get/get.dart';class DependencyManagerMain extends StatefulWidget {const DependencyManagerMain({super.key});@overrideState<DependencyManagerMain> createState() => _DependencyManagerMainState();
}class _DependencyManagerMainState extends State<DependencyManagerMain>with SingleTickerProviderStateMixin {late TabController _tabController;@overridevoid initState() {super.initState();// 初始化 TabController_tabController = TabController(length: 3, vsync: this);}@overridevoid dispose() {// 销毁 TabController_tabController.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(body: TabBarView(controller: _tabController,children: [HomePage(),FavoritesTab(),const SettingsTab(),],),bottomNavigationBar: TabBar(controller: _tabController,tabs: const [Tab(icon: Icon(Icons.home), text: "首页"),Tab(icon: Icon(Icons.star), text: "收藏"),Tab(icon: Icon(Icons.settings), text: "设置"),],),);}
}class HomeController extends GetxController {var count = 0.obs;void increment() {count++;}
}
class HomePage extends StatelessWidget {HomePage({super.key});final HomeController controller = Get.find<HomeController>();@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('首页'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [// 使用 Obx 来监听 count 的变化Obx(() => Text('Count: ${controller.count}',style: const TextStyle(fontSize: 20),)),const SizedBox(height: 20),ElevatedButton(onPressed: controller.increment,child: const Text('Increment'),),],),),);}
}class FavoritesTab extends StatelessWidget {FavoritesTab({super.key});final HomeController controller = Get.find<HomeController>();@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('收藏'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [// 使用 Obx 来监听 count 的变化Obx(() => Text('点击次数: ${controller.count}',style: const TextStyle(fontSize: 20),)),const SizedBox(height: 20),],),),);}
}class SettingsTab extends StatelessWidget {const SettingsTab({super.key});@overrideWidget build(BuildContext context) {return const Center(child: Text('Settings Tab Content'),);}
}

2.Get.lazyPut

        可以懒加载一个依赖,这样它只有在使用时才会被实例化。这对于计算代价高的类来说非常有用,或者如果你想在一个地方实例化几个类(比如在Bindings类中),而且你知道你不会在那个时候使用这个类。
        Get.lazyPut方法用于延迟创建依赖实例,只有在第一次使用时才会创建。

        这里就不写demo了,感兴趣的话,可以参考上一个例子中的demo写Demo测试一下。

///只有当第一次使用Get.find<ApiMock>时,ApiMock才会被调用。
Get.lazyPut<ApiMock>(() => ApiMock());

Get.lazyPut<FirebaseAuth>(
  () {
    // ... some logic if needed
    return FirebaseAuth();
  },
  tag: Math.random().toString(),
  fenix: true
)

Get.lazyPut<Controller>( () => Controller() )

3.Get.putAsync

        如果你想注册一个异步实例,你可以使用Get.putAsync
        Get.putAsync方法用于异步创建依赖实例,适用于需要进行异步操作的实例化过程。

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

        我们还可以设置如下参数:

Get.putAsync<S>(

  // 必备:一个将被执行的异步方法,用于实例化你的类。
  AsyncInstanceBuilderCallback<S> builder,

  // 可选:和Get.put()一样,当你想让同一个类有多个不同的实例时,就会用到它。
  // 必须是唯一的
  String tag,

  // 可选:与Get.put()相同,当你需要在整个应用程序中保持该实例的生命时使用。
  // 默认值为false
  bool permanent = false
)

4.GetView、GetxView 和GetxController

4.高级依赖注入

1.使用Get.create

        Get.create方法用于每次请求时创建一个新的依赖实例,适用于需要多次创建的依赖。

void main() {Get.create<MyController>(() => MyController());runApp(MyApp());
}

2.依赖生命周期管理

        GetX 提供了三种依赖生命周期管理模式:

        Permanent:永久存在,直到应用关闭。

        Singleton:默认模式,实例在第一次创建后存在于整个应用生命周期内。

        Transient:每次请求时创建新的实例。

        模块化依赖注入:
         在大型项目中,可以将依赖注入模块化,便于管理和维护。

class AppBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<MyController>(() => MyController());
  }
}

void main() {
  runApp(GetMaterialApp(
    initialBinding: AppBinding(),
    home: MyApp(),
  ));
}

5.依赖管理中的常见问题及解决方案

1.依赖未能正确注入或找到

        例如在下面的例子中,我在首页调用Get.find的方法,但是想相应的实例方法却没有被创建。

CounterController counterController = Get.find();

图2.依赖未能正确注入或找到

        控制台日志输出如下:

        图3.控制台输入日志

        解决的方法也很简单,就是在调用之前确保相应的GetxController被实例化。

        例如我们可以在app启动之前,实例化相应的控制器或者初始化的时候就绑定相应的GetxController。

图3.全局绑定GetxController

2.实例化过程中的性能问题

        在使用 GetX 时,如果不小心,可能会引入性能问题。例如,不恰当地更新整个 UI 而不是局部更新,或者频繁地创建和销毁控制器。下面是一个示例,展示了如何使用 GetX 并说明可能的性能问题,以及如何优化这些问题。

        在下面的代码中,PerformancelssueExample类展示了可能的性能问题。每次计数器值变化时,整个 Column 会被重建,导致性能下降。

import 'package:flutter/material.dart';
import 'package:get/get.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return GetMaterialApp(home: HomePage(),);}
}class HomeController extends GetxController {var counter = 0.obs;void increment() => counter.value++;
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {final HomeController controller = Get.put(HomeController());return Scaffold(appBar: AppBar(title: Text('GetX Performance Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('You have pushed the button this many times:'),GetX<HomeController>(builder: (controller) {return Text('${controller.counter.value}',style: Theme.of(context).textTheme.headline4,);},),PerformanceIssueExample(),],),),floatingActionButton: FloatingActionButton(onPressed: controller.increment,tooltip: 'Increment',child: Icon(Icons.add),),);}
}class PerformanceIssueExample extends StatelessWidget {@overrideWidget build(BuildContext context) {final HomeController controller = Get.find();return Column(children: [Obx(() {print("Rebuilding entire Column");return Column(children: [for (int i = 0; i < 100; i++)Text('Item $i'),Text('Counter: ${controller.counter.value}'),],);}),ElevatedButton(onPressed: controller.increment,child: Text('Increment Counter'),),],);}
}

         优化建议:

  1. 避免在可观察值变化时重建整个组件树。
  2. 将变化范围限制在最小的部件中,以减少重建次数

  3. 使用 GetX 或 Obx 只在必要时更新 UI

3.依赖生命周期管理不当导致的内存泄漏

       在使用 GetX 时,内存管理是一个重要的考虑因素。如果不正确地管理控制器和依赖项,可能会导致内存泄漏。下面是一个示例,说明 GetX 内存管理中的常见问题及其解决方案。

1.示例代码

        假设我们有一个简单的计数器应用,每次进入一个新页面都会创建一个新的控制器实例,但未正确释放旧的控制器实例,这会导致内存泄漏。

        以下面代码为例:

import 'package:flutter/material.dart';
import 'package:get/get.dart';void main() {runApp(MyApp());
}class CounterController extends GetxController {var count = 0.obs;void increment() => count++;
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return GetMaterialApp(home: HomePage(),);}
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home Page'),),body: Center(child: ElevatedButton(onPressed: () {Get.to(CounterPage());},child: Text('Go to Counter Page'),),),);}
}class CounterPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 不推荐的做法:每次进入页面时创建新的控制器实例final CounterController controller = Get.put(CounterController());return Scaffold(appBar: AppBar(title: Text('Counter Page'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[GetX<CounterController>(builder: (_) {return Text('Count: ${controller.count.value}');},),ElevatedButton(onPressed: controller.increment,child: Text('Increment'),),],),),);}
}

        在这个示例中,每次导航到 CounterPage 时,都会创建一个新的 CounterController 实例,但未正确释放旧的实例,这会导致内存泄漏。

2.解决方案

        为了避免内存泄漏,可以使用 Get.put 或 Get.lazyPut 在合适的地方创建和释放控制器实例,并使用 Get.delete 方法在不需要时释放控制器实例。

        修改后的代码如下:

import 'package:flutter/material.dart';
import 'package:get/get.dart';void main() {runApp(MyApp());
}class CounterController extends GetxController {var count = 0.obs;void increment() => count++;
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return GetMaterialApp(home: HomePage(),);}
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home Page'),),body: Center(child: ElevatedButton(onPressed: () {Get.to(CounterPage());},child: Text('Go to Counter Page'),),),);}
}class CounterPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 推荐的做法:使用 Get.put 只创建一个控制器实例,直到不再需要final CounterController controller = Get.put(CounterController());return Scaffold(appBar: AppBar(title: Text('Counter Page'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[GetX<CounterController>(builder: (_) {return Text('Count: ${controller.count.value}');},),ElevatedButton(onPressed: controller.increment,child: Text('Increment'),),],),),);}@overridevoid dispose() {// 当页面销毁时,释放控制器实例Get.delete<CounterController>();super.dispose();}
}

        修改之后的实例中:

1.正确使用Get.put:在 CounterPage 页面创建时,只创建一个 CounterController 实例。

2.使用Get.put和Get.lazyPut:根据需要创建和管理控制器实例。

3.释放控制器实例:在页面销毁时,通过 Get.delete<CounterController>() 方法释放控制器实例,防止内存泄漏。

6. 参考资料

        1.Getx官方文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/48594.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java基于ssm+vue 药品网购平台

1用户前台功能模块 1.1前台首页 前台首页详情页面&#xff1a;首页、药品信息、疫情常识、保健品推荐、个人中心、后台管理、购物车等操作。程序效果图如下图1所示&#xff1a; 前台页面等内容&#xff0c;如图1所示。 1.2个人中心 在前台页面查看个人中心用户注册、登录&am…

【proteus经典实战】LCD滚动显示汉字

一、简介 Proteus是一款功能丰富的电子设计和仿真软件&#xff0c;它允许用户设计电路图、进行PCB布局&#xff0c;并在虚拟环境中测试电路功能。这款软件广泛应用于教育和产品原型设计&#xff0c;特别适合于快速原型制作和电路设计教育。Proteus的3D可视化功能使得设计更加直…

多任务高斯过程数学原理和Pytorch实现示例

高斯过程其在回归任务中的应用我们都很熟悉了&#xff0c;但是我们一般介绍的都是针对单个任务的&#xff0c;也就是单个输出。本文我们将讨论扩展到多任务gp&#xff0c;强调它们的好处和实际实现。 本文将介绍如何通过共区域化的内在模型(ICM)和共区域化的线性模型(LMC)&…

【Linux知识点汇总】07 Linux系统防火墙相关命令,关闭和开启防火墙、开放端口号

​完整系列文章目录 【Linux知识点汇总】 心血来潮突然想起之前写过的系列文章【Linux知识点汇总】还未完结&#xff0c;那么今天就继续吧 说明&#xff1a;这个系列的内容&#xff0c;在系列【Linux服务器Java环境搭建】中会经常用到&#xff0c;大家可以自行查找相关命令 一、…

Docker搭建本地私有仓库

目录 1.下载运行registry 镜像 2.添加私有镜像仓库地址 3.为镜像添加标签 4.上传到私有仓库 5.查看私有仓库的所有镜像 6.测试私有仓库下载 1.下载运行registry 镜像 docker pull registry docker run -d -v /data/registry:/var/lib/registry -p 5000:5000 --restartal…

PostgreSQL使用(二)——插入、更新、删除数据

说明&#xff1a;本文介绍PostgreSQL的DML语言&#xff1b; 插入数据 -- 1.全字段插入&#xff0c;字段名可以省略 insert into tb_student values (1, 张三, 1990-01-01, 88.88);-- 2.部分字段插入&#xff0c;字段名必须写全 insert into tb_student (id, name) values (2,…

vue3【详解】跨组件通信 -- 依赖注入 provide inject

用于解决跨组件&#xff08;父组件与所有后代&#xff09;数据通信 提供数据 provide 传出数据的组件 &#xff08;通常为父辈组件&#xff09;提供数据 <script setup> import { provide } from vueprovide(/* 注入名 */ message, /* 值 */ hello!) </script>pro…

pycharm中运行.sh文件

最近在跑一个项目代码&#xff0c;里面要运行.sh文件。于是配置了下如何在pycharm中正常运行.sh文件。 首先安装好git&#xff0c;然后 File—>Settings—>Tools—>Terminal—>Shell path&#xff0c;将cmd.exe改成刚刚下载的git的路径&#xff0c;注意选择的是s…

web服务器——虚拟主机配置实战

搭建静态网站 —— 基于 http 协议的静态网站 实验 1 &#xff1a;搭建一个 web 服务器&#xff0c;访问该服务器时显示 “hello world” 欢迎界面 。 实验 2 &#xff1a;建立两个基于 ip 地址访问的网站&#xff0c;要求如下 该网站 ip 地址的主机位为 100 &#xff0c;设置…

web——搭建静态网站——基于http协议的静态网站

实验 4 &#xff1a;建立两个基于域名访问的网站&#xff0c;要求如下&#xff1a; 新建一个网站&#xff0c;域名为 www.ceshi.com &#xff0c;设置网站首页目录为 /www/name &#xff0c;网页内容为 this is test 。 新建一个网站&#xff0c;域名为 rhce.first.day &…

阵列信号处理学习笔记(一)--阵列信号处理定义

阵列信号 阵列信号处理学习笔记&#xff08;一&#xff09;–阵列信号处理定义 阵列信号处理学习笔记&#xff08;二&#xff09;–空域滤波基本原理 文章目录 阵列信号前言一、阵列信号处理定义1.1 信号1.2 阵列 二、雷达数据中哪些属于空间采样总结 前言 MOOC 阵列信号处理…

在线 PDF 制作者泄露用户上传的文档

两家在线 PDF 制作者泄露了数万份用户文档&#xff0c;包括护照、驾驶执照、证书以及用户上传的其他个人信息。 我们都经历过这样的情况&#xff1a;非常匆忙&#xff0c;努力快速制作 PDF 并提交表单。许多人向在线 PDF 制作者寻求帮助&#xff0c;许多人的祈祷得到了回应。 …

FOG Project 文件名命令注入漏洞复现(CVE-2024-39914)

0x01 产品简介 FOG是一个开源的计算机镜像解决方案,旨在帮助管理员轻松地部署、维护和克隆大量计算机。FOG Project 提供了一套功能强大的工具,使用户能够快速部署操作系统、软件和配置设置到多台计算机上,从而节省时间和精力。该项目支持基于网络的 PXE 启动、镜像创建和还…

【人工智能】AI音乐创作兴起与AI伦理的新视角

文章目录 &#x1f34a;AI音乐创作&#xff1a;一键生成&#xff0c;打造你的专属乐章&#x1f34a;1 市面上的AI音乐应用1.1 Suno AI1.2 网易天音 &#x1f34a;2 AI音乐创作的流程原理(直接制作可跳到第3点)2.1 AI音乐流派2.2 AI音乐风格2.3 AI音乐的结构顺序2.5 选择AI音乐乐…

手机如何播放电脑的声音?

准备工具&#xff1a; 有线耳机&#xff0c;手机&#xff0c;电脑&#xff0c;远控软件 1.有线耳机插电脑上 2.电脑安装pc版远控软件&#xff0c;手机安装手机端控制版远控软件 3.手机控制电脑开启声音控制 用手机控制电脑后&#xff0c;打开声音控制&#xff0c;电脑播放视频…

uniapp vue3 上传视频组件封装

首先创建一个 components 文件在里面进行组件的创建 下面是 vvideo组件的封装 也就是图片上传组件 只是我的命名是随便起的 <template><!-- 上传视频 --><view class"up-page"><!--视频--><view class"show-box" v-for"…

Netty HTTPS服务端高并发宕机案例

读李林峰《netty进阶指南》于第18章有感。特此记录一下问题的现象&#xff0c;以及他是如何排障的&#xff0c;以此加深理解 目录标题 事件梳理排查事后分析如何解决总结 事件梳理 某系统内部两个模块之间采用 HTTPS 通信。 某天&#xff1a; 客户端某时间吞吐量为0&#xf…

海思arm-hisiv400-linux-gcc 交叉编译rsyslog 记录心得

需要编译rsyslog,参考海思3536平台上rsyslog交叉编译、使用-CSDN博客和rsyslog移植&#xff08;亲测成功&#xff09;_rsyslog交叉编译-CSDN博客 首先下载了要用到的一些库的源码&#xff0c;先交叉编译这些库 原来是在centos6上交叉编译的&#xff0c;结果编译时报缺少软件要…

MySQL练习02

题目 步骤 创建数据库 create database mydb8_worker; #创建数据库 use mydb8_worker; #使用数据库 创建表 create table t_worker( department_id int(11) not null comment 部门号, worker_id int(11) primary key not null comment 职工号, worker_date date not …

数据结构 - 栈(精简介绍)

文章目录 普通栈Stack用法Q 最长有效括号 单调栈Q 接雨水 普通栈 栈就是一个先进后出的结构 想象一个容器&#xff0c;往里面一层一层放东西&#xff0c;最早放进去的东西被压在下面&#xff08;所以放元素也叫压栈&#xff09;&#xff0c;要拿到这个最低层的东西需要先把上面…