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

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

视频

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

https://www.bilibili.com/video/BV1EG411X7zz/

前言

原文 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() 通过泛型查找对象

控制器 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