Flutter依赖注入插件inject_annotation的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter依赖注入插件inject_annotation的使用

编译时依赖注入

编译时依赖注入是一种在编译时而不是运行时管理应用程序依赖的技术。这提供了许多好处,包括提高性能、减少代码大小和更好的编译时错误检查。在Dart和Flutter中,编译时依赖注入通过使用@inject@provides注解以及ComponentModule类来实现。

入门指南

添加依赖

要在您的Dart或Flutter项目中使用此库,需要在pubspec.yaml文件中添加依赖:

// dart
$ dart pub add inject_annotation
$ dart pub add inject_generator build_runner --dev

// flutter
$ flutter pub add inject_annotation
$ flutter pub add inject_generator build_runner --dev

生成代码

要生成代码,需要运行构建工具:

// dart
$ dart run build_runner build

// flutter
$ flutter pub run build_runner build

Component

要在Dart或Flutter应用程序中使用编译时依赖注入,需要创建一个Component类。这是一个用@component@Component([])(如果有模块)注解的抽象类。

Component中,可以定义返回所需类实例的方法(例如,Repository get repository在下面的示例中)。

@component
abstract class MainComponent {
  static const create = g.MainComponent$Component.create;

  @inject
  Repository get repository;
}

注入类型

要将类型添加到依赖图中,可以用@inject注解其类。例如:

@inject
class Repository {
  const Repository(this.apiClient);

  final FakeApiClient apiClient;

  Future<String> getGreeting({required String name}) => apiClient.getGreeting(name: name);
}

注意,不能将@inject注解添加到第三方库中的类。

模块

模块是用@module注解的类。在那里,可以用@provides注解定义依赖。

@provides注解的方法告诉如何提供类的实例。函数参数是该类型的依赖。

@module
class ApiModule {
  @provides
  @singleton
  FakeApiClient apiClient() => FakeApiClient();
}

然后可以在Component中包含该模块:

@Component([ApiModule])
abstract class MainComponent {
  static const create = g.MainComponent$Component.create;

  @inject
  Repository get repository;
}

单例

@singleton注解用于指示应仅创建所提供类型的单个实例并在整个应用程序中共享。这可以通过避免不必要的对象创建来帮助提高性能和减少内存使用。

要使用@singleton,只需将其作为注解添加到提供实例的方法中:

@module
class ApiModule {
  @provides
  @singleton
  FakeApiClient apiClient() => FakeApiClient();
}

常见问题

什么是编译时?

所有依赖注入都在编译时作为构建过程的一部分进行分析、配置和生成,并不依赖于任何运行时设置或配置(如使用dart:mirrors的反射)。这在代码大小和性能方面提供了最佳体验(几乎与手写代码相同),并且允许我们在编译时提供错误和警告,而不是依赖于运行时。

示例代码

import 'package:inject_annotation/inject_annotation.dart';

import 'main.inject.dart' as g;

Future<void> main() async {
  /// 创建一个 [MainComponent] 实例以访问依赖图。
  final mainComponent = g.MainComponent$Component.create();

  /// 使用仓库获取 "World" 的问候语。
  print(await mainComponent.repository.getGreeting(name: 'World'));
}

/// 访问依赖图的入口点。
/// [Component] 声明返回所需类型实例的属性。
@Component([ApiModule])
abstract class MainComponent {
  /// 创建 [MainComponent] 实例的工厂方法。
  static const create = g.MainComponent$Component.create;

  /// 返回一个 [Repository] 实例以供其他类使用。
  @inject
  Repository get repository;
}

/// [Repository] 依赖于 [FakeApiClient] 实例。
/// 其依赖项通过构造函数注入。
@inject
class Repository {
  /// 创建一个新的 [Repository] 实例,给定 [apiClient]。
  const Repository(this.apiClient);

  /// 由该类使用的 [FakeApiClient] 实例。
  final FakeApiClient apiClient;

  /// 返回包含给定名称问候消息的 [Future]。
  Future<String> getGreeting({required String name}) => apiClient.getGreeting(name: name);
}

/// [module] 声明如何获取特定类型的实例。
/// 对于无法使用 [inject] 注解的第三方库,模块是必需的。
@module
class ApiModule {
  /// 返回一个新的 [FakeApiClient] 实例以注入到其他类中。
  @provides
  @singleton
  FakeApiClient apiClient() => FakeApiClient();
}

/// 一个假的 API 客户端,返回给定名称的问候消息。
/// 在实际实现中,这通常是来自 Chopper 等库的客户端。
class FakeApiClient {
  /// 返回包含给定名称问候消息的 [Future]。
  Future<String> getGreeting({required String name}) => Future.value('Hello $name!');
}

以上代码展示了如何在Flutter项目中使用inject_annotation进行依赖注入。通过这种方式,可以更高效地管理和使用应用程序的依赖关系。


更多关于Flutter依赖注入插件inject_annotation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter依赖注入插件inject_annotation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用inject_annotation插件进行依赖注入的示例。inject_annotation是一个用于Flutter的依赖注入库,它允许你通过注解的方式管理和注入依赖项。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加inject_annotation及其运行时库inject的依赖:

dependencies:
  flutter:
    sdk: flutter
  inject_annotation: ^x.y.z  # 请使用最新版本号
  inject: ^x.y.z             # 请使用最新版本号

然后运行flutter pub get来安装依赖。

2. 创建依赖项和服务

接下来,创建一个简单的服务类,并使用@Injectable注解标记它:

// services/api_service.dart
import 'package:inject/inject.dart';

@Injectable(singleton: true)  // 设置为单例
class ApiService {
  void fetchData() {
    // 模拟API调用
    print("Fetching data from API...");
  }
}

3. 配置依赖注入

在你的应用程序的入口文件(通常是main.dart)中,配置依赖注入容器:

// main.dart
import 'package:flutter/material.dart';
import 'package:inject/inject.dart';
import 'services/api_service.dart';

void main() {
  // 创建并配置依赖注入容器
  var graph = Graph();
  graph.registerFactory<ApiService>(() => ApiService());

  // 获取依赖注入的实例
  var apiService = graph.get<ApiService>();

  // 在这里你可以使用apiService做一些初始化操作,比如调用fetchData
  apiService.fetchData();

  // 运行Flutter应用
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Inject Example'),
        ),
        body: Center(
          child: Text('Check console for API fetch message'),
        ),
      ),
    );
  }
}

注意:上面的代码直接在main函数中使用了依赖注入,但在实际项目中,你可能希望在组件级别或更细粒度的地方使用依赖注入。

4. 在组件中使用依赖注入

为了更灵活地在组件中使用依赖注入,你可以使用Provider或类似的方式来传递依赖项。以下是一个更复杂的示例,展示如何在Widget中使用依赖注入:

// main.dart (改进版)
import 'package:flutter/material.dart';
import 'package:inject/inject.dart';
import 'services/api_service.dart';

// 创建一个全局的Graph实例
var graph = Graph();

void main() {
  // 配置依赖注入
  graph.registerFactory<ApiService>(() => ApiService());

  runApp(
    GraphProvider(
      graph: graph,
      child: MyApp(),
    ),
  );
}

// 包装一个Provider,用于传递Graph实例
class GraphProvider extends StatelessWidget {
  final Graph graph;
  final Widget child;

  GraphProvider({required this.graph, required this.child});

  @override
  Widget build(BuildContext context) {
    return InjectorProvider(
      graph: graph,
      child: child,
    );
  }
}

// 使用@Provide注解的Widget
@Provide(type: ApiService)
class MyHomePage extends StatelessWidget {
  @Inject! ApiService apiService;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Inject Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            apiService.fetchData();
          },
          child: Text('Fetch Data'),
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),  // 使用MyHomePage,它会自动注入ApiService
    );
  }
}

注意@Provide@Inject注解的用法可能因inject_annotation插件的版本不同而有所变化。如果上述代码中的注解方式不适用,请参考插件的官方文档或源码进行调整。

以上示例展示了如何使用inject_annotation插件进行基本的依赖注入。在真实项目中,你可能需要根据项目需求进行更多的配置和优化。

回到顶部