Flutter中的依赖注入

我们目前正在与Flutter一起进行实验,同时开发我们的副项目以应对同事的挑战。 这个辅助项目也应该被视为一个游乐场,在这里我们可以检查是否可以在更严重的项目中使用Flutter。 这就是为什么我们要在那里使用一些方法的原因,而这种方法看起来像是对如此小的项目的过度设计。


因此,第一个问题是我们可以使用什么进行依赖注入。 在互联网上进行的快速搜索显示,有2个库得到了好评: get_itkiwi 。 由于get_it原来是服务定位器(并且我不喜欢这种模式),所以我打算使用奇异果,它看起来更有前途,但是后来我找到了另一个库: inject.dart 。 它在很大程度上受到Dagger库的启发,在我们使用其他Android项目中的最新库时,我决定深入研究它。


值得一提的是,尽管该库位于Google GitHub存储库中,但它不是Google的官方库,因此目前不提供支持:


该库当前是按现状提供(开发人员预览),因为它是从Google内部的内部存储库中开源的。 因此,我们目前无法处理错误或功能请求。

尽管如此,看起来该库已完成我们现在需要的所有工作,因此我想分享一些有关如何在项目中使用该库的信息。


安装方式


由于官方存储库中没有软件包,因此我们必须手动安装。 我更喜欢将其作为git子模块来执行,因此我在项目源目录中创建了一个文件夹vendor ,并从该目录运行以下命令:


 git submodule add https://github.com/google/inject.dart 

现在我们可以通过pubspec.yaml添加到pubspec.yaml


 dependencies: // other dependencies here inject: path: ./vendor/inject.dart/package/inject dev_dependencies: // other dev_dependencies here build_runner: ^1.0.0 inject_generator: path: ./vendor/inject.dart/package/inject_generator 

使用方法


我们通常期望DI库具有哪些功能? 让我们看一些常见的用例:


混凝土类注射


可以这样简单:


 import 'package:inject/inject.dart'; @provide class StepService { // implementation } 

我们可以将其与Flutter小部件一起使用,例如:


 @provide class SomeWidget extends StatelessWidget { final StepService _service; SomeWidget(this._service); } 

接口注入


首先,我们需要定义一个带有一些实现类的抽象类,例如:


 abstract class UserRepository { Future<List<User>> allUsers(); } class FirestoreUserRepository implements UserRepository { @override Future<List<User>> allUsers() { // implementation } } 

现在,我们可以在模块中提供依赖项:


 import 'package:inject/inject.dart'; @module class UsersServices { @provide UserRepository userRepository() => FirestoreUserRepository(); } 

提供者


如果我们不需要注入某个类的实例,而需要注入一个提供者,那将给我们每次该类的新实例,该怎么办? 还是如果我们需要懒散地解决依赖关系,而不是在构造函数中获取具体实例呢? 我既没有在文档中找到它(因为根本没有文档),也没有在提供的示例中找到它,但是它实际上以这种方式工作,您可以请求一个返回所需实例的函数,并将其正确注入。


我们甚至可以这样定义一个帮助程序类型:


 typedef Provider<T> = T Function(); 

并在我们的课程中使用它:


 @provide class SomeWidget extends StatelessWidget { final Provider<StepService> _service; SomeWidget(this._service); void _someFunction() { final service = _service(); // use service } } 

辅助注射


没有内置功能来注入仅需要在运行时知道参数的对象,因此在这种情况下,我们可以将通用模式与工厂一起使用:创建一个工厂类,该类在构造函数中获取所有编译时的依赖项并将其注入,并提供一个带有运行时参数的工厂方法,它将创建所需的实例。


单例,限定符和异步注入


是的,该库支持所有这些。 官方示例中实际上有一个很好的解释。


接线


为了使一切正常工作的最后一步是创建一个注入器(又名Dagger组件),例如:


 import 'main.inject.dart' as g; @Injector(const [UsersServices, DateResultsServices]) abstract class Main { @provide MyApp get app; static Future<Main> create( UsersServices usersModule, DateResultsServices dateResultsModule, ) async { return await g.Main$Injector.create( usersModule, dateResultsModule, ); } } 

这里的UserServicesDateResultsServices是先前定义的模块, MyApp是应用程序的根窗口小部件, main.inject.dart是自动生成的文件(稍后会对此进行详细介绍)。


现在,我们可以这样定义我们的主要功能:


 void main() async { var container = await Main.create( UsersServices(), DateResultsServices(), ); runApp(container.app); } 

跑步


inject与代码生成一起工作时,我们需要使用构建运行器来生成所需的代码。 我们可以使用以下命令:


 flutter packages pub run build_runner build 

watch命令以保持源代码自动同步:


 flutter packages pub run build_runner watch 

但是这里有一个重要的时刻:默认情况下,代码将生成到cache文件夹中,Flutter当前不支持此功能(尽管为了解决此问题正在进行中)。 因此,我们需要添加具有以下内容的文件inject_generator.build.yaml


 builders: inject_generator: target: ":inject_generator" import: "package:inject_generator/inject_generator.dart" builder_factories: - "summarizeBuilder" - "generateBuilder" build_extensions: ".dart": - ".inject.summary" - ".inject.dart" auto_apply: dependents build_to: source 

它的内容实际上与文件vendor/inject.dart/package/inject_generator/build.yaml相同,除了以下一行: build_to: cache已替换为build_to: source


现在我们可以运行build_runner ,它将生成所需的代码(如果某些依赖项build_runner ,则会提供错误消息),然后我们可以照常运行Flutter build。


获利


仅此而已。 您还应该检查库本身提供的示例 ,如果您对Dagger库有一定的经验,那么inject对您真的很熟悉。

Source: https://habr.com/ru/post/zh-CN446134/


All Articles