Flutter插件管理插件managed的使用

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

Flutter插件管理插件managed的使用

特性

  • 多类型依赖注册。
  • 基于作用域的依赖注册。
  • 简单的注入API。

依赖注册

该库使用模块(Module)原语来执行依赖注册。当你想为注入注册一个依赖时,需要完成以下步骤:

  1. 定义一个模块,在其中声明依赖注册代码。
class AppModule extends Module {
  AppModule() : super({});
}

你可以定义多个模块,模块的数量取决于你的应用程序架构。

  1. 声明一个或多个分配给static final变量的依赖注册实例。依赖注册由Manage类执行。
class AppModule extends Module {
  AppModule() : super({});
  
  static final service = Manage(Service.new);
}

创建新的Manage实例的完整代码如下:

class AppModule extends Module {
  AppModule() : super({});

  static final service = Manage<Service>(
      ServiceFactory, 
      scope: Scope.unique, 
      dependsOn: [],
  );
}

在上面的例子中,你可以看到一些可选参数。参数scope用于提供特定的作用域,在其中将管理依赖项的实例。参数dependsOn用于初始化其他必要的依赖项的注册。

需要注意的是,静态变量的值在第一次使用时被初始化。这意味着直到你访问变量之前,其值不会被创建。这就是为什么我们在dependsOn参数中应该使用其他静态变量的原因。

构造函数中提供的工厂可以是一个类构造器:

Manage(Service.new);

或者你可以提供闭包:

Manage(() => Service());

在简单的情况下,Manage实例的泛型类型会自动推断出来。但在某些情况下,你应该显式地定义泛型参数:

Manage<Service>(() => Service());
  1. 在父构造函数中使用某些静态变量。
class AppModule extends Module {
  AppModule() : super({service});
  
  static final service = Manage(Service.new, dependsOn: [client]);
  static final client = Manage(HttpClient.new);
  
}

这一步是必要的,因为有些静态变量可能未被初始化。这仅适用于那些尚未在其他地方使用的变量。在实际代码中,我们通常会遇到这样的情况,即某些依赖项依赖于其他依赖项。在这种情况下,访问尚未引用过的构造函数中的变量将导致这些变量及其所有依赖项的值被初始化。

在上面的例子中,当我们使用service变量时,其值将被创建,并且client变量的值也将被创建。

作用域

作用域是一种机制,用于控制注入行为。该库提供了三种不同的Scope实现:

  • unique - 每次创建新实例。
  • singleton - 只创建一次实例,并且实例永远不会被丢弃。
  • cached - 创建新实例并存储,直到调用reset方法。当调用reset方法时,先前创建的实例将被丢弃。

每个从作用域提供的实例都是通过构造函数中提供的工厂创建的。如果你使用cachedsingleton作用域,则从作用域提供的实例将与工厂一起存储。这使我们能够进行不同类型的注册,但使用相同的工厂,并且在访问时共享相同的实例。

  1. 在你想使用依赖的地方混合Managed混入。
class Service with Managed {
  
}

Managed混入重定义了noSuchMethod以实现注入行为(有关混入实现的更多细节,请参阅源代码)。

  1. 定义提供依赖的方法。
class Service with Managed {
  T _httpClient<T extends HttpClient>();
}

在下面的例子中,我们定义了一个具有泛型参数T的方法,该参数应扩展HttpClient并且没有方法体。这种声明在运行时会委托给noSuchMethod,在那里我们可以访问调用详情。Invocation类包含有关调用时泛型参数的实际值的信息。在我们的例子中,泛型参数的实际值将是HttpClient,因为我们通过具体类型它必须实现来绑定泛型参数。由于我们在调用时没有指定泛型参数,所以参数的值等于限定类型。并且因为我们有来自泛型参数值的具体依赖类型,所以我们可以在相等类型中找到Manage实例,然后使用具体的类型工厂和提供的作用域获取该类型的实例。

如果没有Managed混入和提供者方法,你可以直接使用模块静态变量来提供依赖项实例。

final service = AppModule.service();

更多关于使用和实现的信息,请参阅源代码和测试。

感谢阅读。


示例代码

import 'dart:convert';
import 'dart:io';

import 'package:managed/managed.dart';

Future<void> main() async {
  /// 创建模块实例以初始化所有依赖项
  ExampleModule();
  final controller = Controller();
  print(await controller.fact());
  controller.increment();
  print(await controller.fact());
  controller.decrement();
  print(await controller.fact());
}

class Controller with Managed {
  var _count = 0;

  /// 提供NumberServiceInstance的方法
  T _service<T extends NumberFactService>();

  void increment() {
    _count += 1;
  }

  void decrement() {
    _count -= 1;
  }

  Future<String> fact() async {
    /// 使用NumberFactService获取事实
    return await _service().numberFact(_count);
  }
}

class NumberFactService with Managed {
  /// 提供HttpClient的方法
  T _client<T extends HttpClient>();

  Future<String> numberFact(int number) async {
    try {
      /// 使用HttpClient请求Numbers API
      HttpClientRequest request =
          await _client().getUrl(Uri.parse('http://numbersapi.com/$number'));

      HttpClientResponse response = await request.close();

      final stringData = await response.transform(utf8.decoder).join();
      return stringData;
    } catch (err, _) {
      print(err);
      rethrow;
    }
  }
}

class ExampleModule extends Module {
  ExampleModule() : super({exampleService});

  /// 注册HttpClient为singleton作用域
  static final client = Manage(
    HttpClient.new,
    scope: Scope.singleton,
  );

  /// 注册NumberFactService为singleton作用域,并标记它依赖于client
  static final exampleService = Manage(
    NumberFactService.new,
    scope: Scope.singleton,
    dependsOn: [client],
  );
}

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

1 回复

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


在Flutter开发中,managed 插件并不是一个官方或广泛认知的插件,但通常提到“管理插件”时,我们可能会联想到Flutter中的依赖管理和插件管理。在Flutter中,插件管理主要是通过pubspec.yaml文件进行的。不过,为了贴近你的问题,我假设你可能是想了解如何通过Flutter的一些工具或代码来更好地管理插件依赖。

Flutter 使用 Dart 的包管理工具 pub 来管理依赖项,包括 Flutter 插件。以下是一些关于如何使用 pubspec.yaml 文件来管理 Flutter 插件的示例代码和说明:

1. 添加插件依赖

pubspec.yaml 文件中添加插件依赖项。例如,如果你想添加一个用于图像挑选的插件,可以这样做:

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^0.8.4+4  # 指定插件版本

2. 获取依赖项

在终端中运行以下命令以获取(安装)所有声明的依赖项:

flutter pub get

3. 使用插件

在 Dart 代码中导入并使用插件。例如,使用 image_picker 插件:

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Image Picker Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _pickImage,
            child: Text('Pick an image'),
          ),
        ),
      ),
    );
  }

  Future<void> _pickImage() async {
    final ImagePicker _picker = ImagePicker();
    final XFile? image = await _picker.pickImage(source: ImageSource.gallery);

    if (image != null) {
      // 处理选中的图片
    }
  }
}

4. 更新依赖项

如果你想更新某个插件到最新版本,可以手动编辑 pubspec.yaml 文件中的版本号,或者运行以下命令来更新所有依赖项到最新版本(注意,这可能会引入不兼容的更改):

flutter pub upgrade --major-versions

或者,仅更新特定的包:

flutter pub upgrade image_picker

5. 查看依赖树

你可以查看项目的依赖树,以了解哪些包被依赖以及它们的版本:

flutter pub deps

6. 清理依赖缓存

在某些情况下,你可能需要清理 Flutter 的依赖缓存。例如,当你遇到奇怪的依赖解析问题时:

flutter pub cache repair

或者,完全删除缓存(不推荐,除非必要):

flutter clean
rm -rf ~/.pub-cache/

请注意,上述命令中的 rm -rf ~/.pub-cache/ 是在 Unix/Linux/macOS 系统上执行的,如果你在 Windows 上,需要手动删除相应的缓存目录。

总结

虽然 managed 插件不是 Flutter 官方或广泛使用的术语,但管理 Flutter 插件通常涉及编辑 pubspec.yaml 文件和使用 flutter pub 命令。希望这些示例和说明能帮助你更好地管理 Flutter 项目中的插件依赖。

回到顶部