Flutter依赖注入插件flutter_inject的使用
Flutter依赖注入插件flutter_inject的使用
flutter_inject
是一个基于标准 Flutter 的 InheritedWidget
的简单依赖注入小部件。
简单保持
Flutter 自带了一个内置的依赖注入系统:InheritedWidget
。
- 注入的依赖项已经根据
BuildContext
进行了范围限制。 - 当
InheritedWidget
从 Widget 树中移除时,内存会自动清理。
Inject
包尊重 Flutter 的架构。
- 它是一个简单的包装器,用于包裹一个简单的
InheritedWidget
。 - 您可以一次性注入一个或多个依赖项。
- 这个小部件会调用您注入的依赖项的
dispose
方法。 - 它允许您覆盖子部件的注入依赖项。
- 您还可以重用父部件的注入依赖项。
1. 这是该包背后的简单 InheritedWidget
:
class _Injected<T> extends InheritedWidget {
static T? get<T>(BuildContext context) {
final injected = context.dependOnInheritedWidgetOfExactType<_Injected<T>>();
return injected?.instance;
}
const _Injected(this.instance, {super.key, required super.child});
final T instance;
[@override](/user/override)
bool updateShouldNotify(_Injected<T> oldWidget) => false;
}
2. 随意注入任意数量的依赖项!
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
// 注入多个依赖项
return InjectAll(
dependencies: [
Dependency<MyApi>((context) => MyApiImpl()),
Dependency<MyRepository>((context) => MyRepositoryImpl(
// 您可以依赖于任何先前注入的依赖项
api: Dependency.get<MyApi>(context),
)),
],
builder: (context) {
// 然后在 Widget 树的任何位置检索您的依赖项
final repository = Dependency.get<MyRepository>(context);
return MyView();
},
);
}
}
class MyView extends StatelessWidget {
const MyView({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
// 注入一个依赖项
return Inject<MyLogic>(
factory: (context) => MyLogic(
// 您可以依赖于任何先前注入的依赖项
repository: Dependency.get<MyRepository>(context),
),
builder: (context) {
// 然后在 Widget 树的任何位置检索您的依赖项
final logic = Dependency.get<MyLogic>(context);
return Scaffold(body: Center(child: Text(logic.getTitle())));
},
);
}
}
3. 不再忘记清理您的应用程序内存!
// Inject 小部件将调用任何注入依赖项的 .dispose() 方法!
class MyLogic {
final controller = StreamController<int>();
[@override](/user/override)
void dispose() => controller.close();
}
4. 通过简单地覆盖子部件的依赖项使测试更高效
// 这里是一个使用 Mocktail(使用 Mockito 的方式相同)的测试示例
class _MyRepositoryMock extends Mock implements MyRepository {}
void main() {
late _MyRepositoryMock mockedRepository;
setUp(() {
mockedRepository = _MyRepositoryMock();
});
testWidgets('Counter increments', (WidgetTester tester) async {
// 为 MyRepository 方法设置模拟行为
when(() => mockedRepository.getToDos()).thenAnswer((_) => [Todo('Bring kids to school')]);
// 构建您的部件并触发帧。
await tester.pumpWidget(
MaterialApp(
// 注入 MyRepository 的模拟版本
home: Inject<MyRepository>(
// 覆盖子部件的 MyRepository 注入
override: true,
factory: (context) => mockedRepository,
builder: (context) => const MyView(),
),
),
);
// 验证没有待办事项列表被渲染
expect(find.text('Bring kids to school'), findsNothing);
// 点击下载按钮(以显示待办事项列表)。
await tester.tap(find.byIcon(Icons.download));
await tester.pump();
expect(find.text('Bring kids to school'), findsOneWidget);
});
}
5. 重用现有父部件的注入实例
class MyView extends StatelessWidget {
const MyView({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return Inject<MyRepository>(
// 如果树中已经注入了一个 MyRepository 实例,则会重用它
// 否则,不用担心,您的部件将注入自己的实例
useExistingInstance: true,
factory: (context) => MyRepositoryImpl(
api: Dependency.get<MyApi>(context),
),
builder: (context) {
final repository = Dependency.get<MyRepository>(context);
return Text('Hello World!');
},
);
}
}
示例代码
以下是一个经典的计数器示例,展示了如何轻松使用 flutter_inject
包。
main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inject/flutter_inject.dart';
void main() => runApp(
const MaterialApp(
title: 'Counter example with the flutter_inject package',
home: CounterView(),
),
);
class CounterView extends StatelessWidget {
const CounterView({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return Inject<CounterLogic>(
factory: (context) => CounterLogic(),
builder: (context) {
final logic = Dependency.get<CounterLogic>(context);
return Scaffold(
appBar: AppBar(title: const Text('Counter demo')),
body: Center(
child: StreamBuilder(
initialData: logic.state,
stream: logic.controller.stream,
builder: (context, snapshot) => Text('Counter: ${snapshot.data}'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: logic.increment,
child: const Icon(Icons.add),
),
);
},
);
}
}
class CounterLogic with Disposable {
int state = 0;
final controller = StreamController<int>();
void increment() => controller.add(++state);
[@override](/user/override)
void dispose() => controller.close();
}
更多关于Flutter依赖注入插件flutter_inject的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter依赖注入插件flutter_inject的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_inject
是一个用于 Flutter 的依赖注入(Dependency Injection, DI)插件,它可以帮助你在 Flutter 应用中更轻松地管理依赖关系。使用依赖注入可以使你的代码更具可测试性、可维护性和灵活性。
安装 flutter_inject
首先,你需要在 pubspec.yaml
文件中添加 flutter_inject
依赖:
dependencies:
flutter:
sdk: flutter
flutter_inject: ^1.0.0 # 请根据最新版本号进行替换
然后运行 flutter pub get
来安装依赖。
基本用法
1. 创建依赖注入容器
首先,你需要创建一个依赖注入容器。通常,你可以在应用的入口文件(如 main.dart
)中创建并配置这个容器。
import 'package:flutter_inject/flutter_inject.dart';
void main() {
// 创建依赖注入容器
final injector = Injector();
// 配置依赖
injector.registerSingleton<MyService>(() => MyServiceImpl());
// 将容器传递给应用
runApp(MyApp(injector));
}
2. 注册依赖
你可以使用 registerSingleton
、registerFactory
和 registerLazySingleton
方法来注册依赖。
registerSingleton
: 注册一个单例,该实例在整个应用生命周期中只会被创建一次。registerFactory
: 每次请求依赖时都会创建一个新的实例。registerLazySingleton
: 注册一个懒加载的单例,只有在第一次请求时才会创建实例。
injector.registerSingleton<MyService>(() => MyServiceImpl());
injector.registerFactory<MyRepository>(() => MyRepositoryImpl());
injector.registerLazySingleton<MyManager>(() => MyManagerImpl());
3. 获取依赖
在需要使用依赖的地方,你可以通过 Injector
实例来获取依赖。
class MyApp extends StatelessWidget {
final Injector injector;
MyApp(this.injector);
[@override](/user/override)
Widget build(BuildContext context) {
final myService = injector.get<MyService>();
return MaterialApp(
home: MyHomePage(myService: myService),
);
}
}
进阶用法
使用 @Inject
注解
flutter_inject
支持使用 @Inject
注解来自动注入依赖。你可以在构造函数或字段上使用 @Inject
注解。
class MyHomePage extends StatelessWidget {
final MyService myService;
@Inject()
MyHomePage({required this.myService});
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Inject Example'),
),
body: Center(
child: Text('Hello, ${myService.greet()}!'),
),
);
}
}
使用 InjectorWidget
InjectorWidget
是一个特殊的 Widget
,它可以帮助你在 Widget
树中自动注入依赖。
class MyHomePage extends InjectorWidget {
[@override](/user/override)
Widget buildWithInjector(BuildContext context, Injector injector) {
final myService = injector.get<MyService>();
return Scaffold(
appBar: AppBar(
title: Text('Flutter Inject Example'),
),
body: Center(
child: Text('Hello, ${myService.greet()}!'),
),
);
}
}