在 getx 中使用 get_it 管理依赖注入

Ducafecat
10 min readNov 3, 2023

--

视频

https://www.youtube.com/watch?v=NBog-RdZ1fQ

前言

原文 https://ducafecat.com/blog/use-get_it-in-getx

上一节讲了 freezed 来强化模型 model 的功能。

今天来说下如何用 get_it 管理 getx 项目的依赖注入 Dependency Injection。

我将会改造我的 《woo实战课程》 代码来示范说明。

代码

https://github.com/ducafecat/flutter_develop_tips/tree/main/flutter_application_get_it

参考

https://pub-web.flutter-io.cn/packages/get_it

知识点

依赖注入(Dependency Injection,DI)是一种软件设计模式,用于管理对象之间的依赖关系。它是控制反转(Inversion of Control,IoC)设计模式的一种具体实现方式。

在传统的对象创建和依赖关系管理方式中,一个对象通常负责创建和管理其所依赖的其他对象。这样的设计可能导致代码之间的紧耦合,并且在测试时难以模拟和替换依赖的对象。

依赖注入通过将对象的创建和依赖关系的管理转移到外部,来解决这些问题。具体而言,依赖注入将对象的依赖通过构造函数、方法参数、属性注入等方式从外部注入到对象中,而不是由对象自身负责创建和管理依赖。这样可以实现对象之间的解耦,提高代码的可测试性、可维护性和可扩展性。

依赖注入的核心思想是:对象只关注自身的职责,而不需要关心如何创建和获取依赖的对象。依赖的对象由外部的容器或框架负责创建和注入进来。这样,对象在使用依赖时只需要声明它们的接口或抽象类,并通过依赖注入的方式获取具体的实现。

下面是一个简单的依赖注入示例:

class Logger {
void log(String message) {
print(message);
}
}

class UserService {
final Logger _logger;

UserService(this._logger);

void login(String username, String password) {
// 用户登录逻辑
_logger.log('用户登录:$username');
}
}

void main() {
final logger = Logger();
final userService = UserService(logger);

userService.login('john', 'password');
}

在上述代码中,UserService 类依赖于 Logger 类来记录日志。通过构造函数将 Logger 对象注入到 UserService 中,使得 UserService 可以在需要时使用 _logger 来记录日志。

通过依赖注入,UserService 类与 Logger 类之间实现了解耦,UserService 不需要关心 Logger 对象的创建和管理,只需要声明它所依赖的接口。这样,我们可以方便地替换或模拟 Logger 对象,以进行单元测试或灵活地切换不同的日志记录实现。

依赖注入的好处包括降低代码的耦合度、提高代码的可测试性和可维护性,以及增强代码的可扩展性和灵活性。它在许多现代的软件开发框架和库中得到广泛应用。

步骤

第一步:创建 getx 项目

猫哥这边使用 vscode 插件 “Flutter GetX Generator — 猫哥” 进行初始

不清楚的可以一进步阅读 《我写了个 vscode 插件提升 flutter getx 开发效率 79% | 猫哥

第二步:加入 get_it

添加组件

$ flutter pub add get_it

工具类 lib/common/utils/wp_http.dart

// 拉取数据 wordpress api
class WPHttp {
late Dio _dio;

WPHttp() {
// 初始 dio
var options = BaseOptions(
baseUrl: Constants.wpApiBaseUrl,
connectTimeout: const Duration(seconds: 10), // 10000, // 10秒
receiveTimeout: const Duration(seconds: 5), // 5000, // 5秒
headers: {},
contentType: 'application/json; charset=utf-8',
responseType: ResponseType.json,
);
_dio = Dio(options);

// 拦截器
_dio.interceptors.add(RequestInterceptors());
}

...

完整代码详见 https://github.com/ducafecat/flutter_develop_tips/blob/main/flutter_application_get_it/lib/common/utils/wp_http.dart

全局注入 lib/global.dart

class Global {
static final getIt = GetIt.instance;
static Future<void> init() async {
// 注册单例 - WPHttp
getIt.registerSingleton<WPHttp>(WPHttp());
}
}

初始 main.dart

Future<void> main() async {
await Global.init();
runApp(const MyApp());
}

第三步:在 getx 控制器中使用

API 拉取数据 lib/common/api/product.dart

import 'package:flutter_application_get_it/global.dart';

import '../index.dart';

/// 商品 api
class ProductApi {
// 读取单例 wphttp
static final _getIt = Global.getIt<WPHttp>();

/// 分类列表
static Future<List<CategoryModel>> categories() async {
var res = await _getIt.get(
'/products/categories',
);

List<CategoryModel> categories = [];
for (var item in res.data) {
categories.add(CategoryModel.fromJson(item));
}
// 排序 menuOrder , 小号在前
categories.sort((a, b) => a.menuOrder!.compareTo(b.menuOrder as int));
return categories;
}

...

Global.getIt<WPHttp>() 通过泛型查找对象

控制器 lib/pages/product_list/controller.dart

class ProductListController extends GetxController {
ProductListController();

// 商品列表
List<ProductModel> products = [];

_initData() async {
products = await ProductApi.products(ProductsReq());
update(["product_list"]);
}

void onTap() {}

@override
void onReady() {
super.onReady();
_initData();
}
}

视图 lib/pages/product_list/view.dart

// 主视图
Widget _buildView() {
return ListView.builder(
itemCount: controller.products.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(controller.products[index].name ?? ""),
subtitle: Image.network(
controller.products[index].images?[0].src ?? "",
height: 100,
fit: BoxFit.cover,
),
);
},
);
}
@override
Widget build(BuildContext context) {
return GetBuilder<ProductListController>(
init: ProductListController(),
id: "product_list",
builder: (_) {
return Scaffold(
appBar: AppBar(title: const Text("product_list")),
body: SafeArea(
child: _buildView(),
),
);
},
);
}

运行

代码

https://github.com/ducafecat/flutter_develop_tips/tree/main/flutter_application_get_it

小结

在项目中使用 get_it 可以单例工具类、懒加载业务类、工厂方式实例不同商品、异步初始需要 await 的对象、全局管理用户Auth登录认证、样式切换、等配置信息,而不是用 GetxService 对象。

感谢阅读本文

如果我有什么错?请在评论中让我知道。我很乐意改进。

flutter 学习路径

© 猫哥 ducafecat.com

end

--

--

Ducafecat
Ducafecat

No responses yet