Flutter依赖注入插件flutter_ioc_container的使用
Flutter依赖注入插件flutter_ioc_container的使用
flutter_ioc_container
flutter_ioc_container
是一个用于Flutter的依赖注入库,它允许你在widget树中管理依赖关系,并可以从BuildContext
访问它们。你还可以用测试替身替换依赖关系进行测试。
ioc_container 是一个Dart的依赖注入和服务定位库。你可以像使用GetIt
包一样在Flutter中使用它。flutter_ioc_container
是ioc_container
的一个扩展,它在整个widget树中暴露了该库的功能,使你可以像使用Provider
一样使用它。它提供了对BuildContext
的扩展方法,让你可以在widget树中的任何位置获取依赖实例。
以下是一个简单的示例,展示了如何使用CounterController
来增加和获取当前值:
FloatingActionButton.extended(
icon: const Icon(Icons.add),
//Increment the value
onPressed: context<CounterController>().increment,
label: Text(
//Display the value
context<CounterController>().value.toString(),
style: Theme.of(context).textTheme.headlineMedium,
),
),
更多详细信息请参阅 ioc_container 文档。
开始使用
安装插件
在你的pubspec.yaml
文件的dependencies部分添加以下行:
flutter_ioc_container: <latest version>
运行flutter pub get
以下载依赖项。
或者,你可以通过命令行安装该包:
flutter pub add flutter_ioc_container
基本用法
- 在你的widget树的根部放置一个
CompositionRoot
widget。这会将容器作为继承widget传播到整个widget树。 - 使用
compose
函数中的builder
向容器添加单例或瞬态依赖。 - 通过
BuildContext
在整个widget树中访问依赖。
以下是基本使用的完整示例:
import 'package:flutter/material.dart';
import 'package:flutter_ioc_container/flutter_ioc_container.dart';
void main() {
runApp(
CompositionRoot(
compose: (builder) => builder.addSingleton((container) => 'test'),
child: MaterialApp(
home: Scaffold(
body: Builder(builder: (context) => const BasicWidget()),
),
),
),
);
}
class BasicWidget extends StatelessWidget {
const BasicWidget({super.key});
@override
Widget build(BuildContext context) => Text(context<String>());
}
作用域
如果你需要一组生命周期短且之后需要释放的依赖,那么widget树中的某个地方需要持有scoped容器。通过调用context.scoped()
获取scoped容器。一种方法是将其放在StatefulWidget
的状态中,并在状态的dispose()
方法中释放内容。
这个例子在didChangeDependencies
中创建了一个scoped容器。它存在于状态的生命周期内,并在小部件树处置此小部件时释放资源。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_ioc_container/flutter_ioc_container.dart';
import 'package:ioc_container/ioc_container.dart';
class DisposableResources {
String display = 'hello world';
void dispose() {
// ignore: avoid_print
print('Disposed');
}
}
void main() {
runApp(
CompositionRoot(
compose: (builder) => builder.addServiceDefinition<DisposableResources>(
ServiceDefinition(
(container) => DisposableResources(),
dispose: (service) => service.dispose(),
),
),
child: MaterialApp(
home: Scaffold(
body: Builder(builder: (context) => const BasicWidget()),
),
),
),
);
}
class BasicWidget extends StatefulWidget {
const BasicWidget({super.key});
@override
State<BasicWidget> createState() => _BasicWidgetState();
}
class _BasicWidgetState extends State<BasicWidget> {
late final IocContainer scopedContainer;
@override
void didChangeDependencies() {
super.didChangeDependencies();
scopedContainer = context.scoped();
}
@override
void dispose() {
super.dispose();
unawaited(scopedContainer.dispose());
}
@override
Widget build(BuildContext context) =>
Text(scopedContainer<DisposableResources>().display);
}
更多关于作用域的信息,请参见这里。
异步注入
如果依赖需要异步初始化,可以使用addAsync
。你可以使用FutureBuilder
widget在对象可用时渲染它。以下是一个示例:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_ioc_container/flutter_ioc_container.dart';
void main() {
runApp(
CompositionRoot(
compose: (builder) => builder.addSingletonAsync(
(container) async => Future<String>.delayed(
const Duration(seconds: 5),
() => 'Hello world!',
),
),
child: MaterialApp(
home: Scaffold(
body: Builder(builder: (context) => const BasicAsyncWidget()),
),
),
),
);
}
class BasicAsyncWidget extends StatefulWidget {
const BasicAsyncWidget({super.key});
@override
State<BasicAsyncWidget> createState() => _BasicAsyncWidgetState();
}
class _BasicAsyncWidgetState extends State<BasicAsyncWidget> {
late final Future<String> future;
@override
void didChangeDependencies() {
// ignore: discarded_futures
future = context.getAsync<String>();
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) => FutureBuilder(
// ignore: discarded_futures
future: future,
builder: (ctx, ss) => ss.connectionState == ConnectionState.done
? Text(ss.data!)
: const CircularProgressIndicator(),
);
}
更多关于异步注入的信息,请参见这里。
用测试替身替换依赖以进行测试
可以通过将configureOverrides
函数传递给根widget来实现。这允许你用测试替身替换依赖。有关完整示例,请参阅小部件测试。
class MyApp extends StatelessWidget {
const MyApp({
super.key,
this.configureOverrides,
});
//This allows us to override the dependencies for testing. Take a look at
//the widget tests
final void Function(IocContainerBuilder builder)? configureOverrides;
@override
Widget build(BuildContext context) => CompositionRoot(
configureOverrides: configureOverrides,
compose: (builder) => builder
//Adds a singleton CounterController to the container
..addSingleton(
(container) => CounterController(),
),
// [...] See the example folder of this package for a full example
);
}
以下是如何用MockValueNotifier
替换依赖的例子:
testWidgets('Basic Smoke Test', (tester) async {
final mockValueNotifier = MockValueNotifier();
await tester.pumpWidget(
MyApp(
//This is how you substitute dependencies with test doubles
configureOverrides: (builder) => builder
.addSingleton<CounterController>((container) => mockValueNotifier),
),
);
//Initial value
expect(find.text('0'), findsOneWidget);
//Tap the button
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
//Verify value
expect(find.text('1'), findsOneWidget);
expect(find.text('0'), findsNothing);
//Ensure we're using the mock dependency
expect(mockValueNotifier.hasCalls, isTrue);
});
更多关于测试的信息,请参见这里。
更多关于Flutter依赖注入插件flutter_ioc_container的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter依赖注入插件flutter_ioc_container的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用flutter_ioc_container
插件进行依赖注入的示例代码。这个插件允许你创建和管理依赖关系,从而使代码更加模块化和易于测试。
首先,你需要在pubspec.yaml
文件中添加flutter_ioc_container
依赖:
dependencies:
flutter:
sdk: flutter
flutter_ioc_container: ^最新版本号 # 请替换为实际最新版本号
然后运行flutter pub get
来获取依赖。
接下来,我们创建一个简单的例子来展示如何使用flutter_ioc_container
。
1. 定义服务接口和实现
首先,定义一个服务接口MyService
以及它的实现MyServiceImpl
。
// my_service.dart
abstract class MyService {
String getData();
}
// my_service_impl.dart
class MyServiceImpl implements MyService {
@override
String getData() {
return "Hello from MyService!";
}
}
2. 设置依赖注入容器
在你的应用程序入口文件(通常是main.dart
)中,设置依赖注入容器并注册服务。
import 'package:flutter/material.dart';
import 'package:flutter_ioc_container/flutter_ioc_container.dart';
import 'my_service.dart';
import 'my_service_impl.dart';
void main() {
// 创建并配置IoC容器
final iocContainer = IoCContainer();
iocContainer.registerSingleton<MyService>(MyServiceImpl());
// 使用Builder来提供依赖
runApp(Builder(
builder: (context) {
return MaterialApp(
home: MyHomePage(iocContainer: iocContainer),
);
},
));
}
class MyHomePage extends StatelessWidget {
final IoCContainer iocContainer;
MyHomePage({required this.iocContainer});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter IoC Container Example'),
),
body: Center(
child: Text(
// 从IoC容器中获取MyService实例并调用getData方法
iocContainer.get<MyService>().getData(),
),
),
);
}
}
3. 使用依赖
在上面的例子中,我们在MyHomePage
构造函数中接收了IoCContainer
实例,并通过iocContainer.get<MyService>()
来获取MyService
的实现。
4. 运行应用程序
现在你可以运行你的Flutter应用程序,应该会看到一个屏幕显示文本“Hello from MyService!”。
注意事项
- 确保你已经正确导入了所有必要的包。
- 在实际应用中,你可能需要在多个地方使用依赖注入,因此可以将
iocContainer
传递给需要的组件,或者考虑使用全局状态管理工具(如Provider)来管理iocContainer
的实例。
这个示例展示了如何使用flutter_ioc_container
进行基本的依赖注入。根据你的需求,你可以进一步扩展这个示例,比如注册多个服务、使用不同的生命周期管理策略等。