Flutter依赖注入与状态管理插件args_riverpod的使用
Flutter依赖注入与状态管理插件args_riverpod的使用
args_riverpod
是一个扩展了 args
包并引入了 Riverpod
能力的库。它提供了一些类来帮助在命令行工具中处理依赖注入和状态管理。
Args Riverpod
免责声明: 此包不是官方 Riverpod 包的一部分。
args
包的扩展版本,结合了 Riverpod
的能力。args_riverpod
引入了以下类:
ProviderCommandRunner
: 提供一个带有根ProviderContainer
(与运行器一起实例化)的CommandRunner
。ProviderCommand
: 提供一个可以访问根ProviderContainer
的Command
。
使用方式与 args
包相同,但有以下不同点:
- 分支命令 可以重写
processArgs
函数以处理它们声明的参数。 - 叶命令 可以重写
processArgs
函数以处理它们声明的参数,并且必须重写execute
函数(代替run
函数)。 - Provider 命令运行器 提供了一个
setGlobalArgsProcessor
,可以注册一个处理器来处理全局参数。
注意: run
已被 execute
替换,这是由于 args
包实现的约束。
根 Provider 容器
在创建 ProviderCommandRunner
时,你可以传递根 ProviderContainer
的 overrides
和 observers
。
ProviderCommandRunner("cli", "A super CLI.", overrides: [], observers: []);
全局选项处理
ProviderCommandRunner
实例化了一个 Riverpod ProviderContainer
,该容器会传递给所有命令/子命令和参数处理器。此容器作为 ref
在 processArgs
和 execute
函数中可用。
为了声明一个全局选项处理器,可以在 ProviderCommandRunner
上调用 setGlobalArgProcessor
。
void main(List<String> arguments) {
ProviderCommandRunner("cli", "A super CLI.")
..setGlobalArgProcessor(GlobalOptionParser())
..addCommand(BranchCommand())
..argParser.addOption('host', help: 'Server host URL')
..argParser.addOption('token', help: 'Server access token')
..run(arguments);
}
class GlobalOptionParser extends ProviderArgsProcessor {
[@override](/user/override)
Future<void> processArgs() async {
print('GlobalOptionParser.processArgs called');
ref.read(hostArgProvider.notifier).state = argResults?['host'];
ref.read(tokenArgProvider.notifier).state = argResults?['token'];
}
}
分支命令选项处理
具有子命令的命令称为“分支命令”,不能直接执行。它应该调用 addSubcommand
(通常从构造函数中调用)来注册子命令。分支命令可以重写 processArgs
来处理相关的参数。
class BranchCommand extends ProviderCommand {
[@override](/user/override)
final name = "branch";
[@override](/user/override)
final description = "branch command";
BranchCommand() {
argParser.addOption('input', help: 'input file path');
addSubcommand(LeafCommand());
}
[@override](/user/override)
void processArgs() {
print('BranchCommand.processArgs called');
ref.read(inputArgProvider.notifier).state = argResults?['input'];
}
}
叶命令选项处理
如果命令没有子命令并且打算运行,则称为“叶命令”。叶命令必须重写 execute
并且可以选择重写 processArgs
。
class LeafCommand extends ProviderCommand {
[@override](/user/override)
final name = "leaf";
[@override](/user/override)
final description = "leaf command";
LeafCommand() {
argParser.addOption('output', help: 'output file path');
}
[@override](/user/override)
void processArgs() {
print('LeafCommand.processArgs called');
ref.read(outputArgProvider.notifier).state = argResults?['output'];
}
[@override](/user/override)
void execute() {
print('LeafCommand.execute called');
ref.read(fooServiceProvider).doSomething();
}
}
完整使用示例
完整的使用示例可参见 这里。
你可以按如下方式运行它:
git clone git@gitlab.com:noan-public/dart-and-flutter/args_riverpod.git && cd args_riverpod
dart "$PWD/args_riverpod/example/args_riverpod_example.dart" --host server.com --token my_token branch --input path/in-file.txt leaf --output path/out-file.txt
示例代码
import 'dart:io';
import 'package:args_riverpod/args_riverpod.dart';
import 'package:args/command_runner.dart';
import 'package:riverpod/riverpod.dart';
// CLI sample call:
// dart "./args_riverpod/example/args_riverpod_example.dart" --host server.com --token my_token branch --input path/in-file.txt leaf --output path/out-file.txt
// CLI main & global options handling
//
void main(List<String> arguments) {
ProviderCommandRunner("cli", "A super CLI.")
..setGlobalArgProcessor(GlobalOptionParser())
..addCommand(BranchCommand())
..argParser.addOption('host', help: 'Server host URL')
..argParser.addOption('token', help: 'Server access token')
..run(arguments);
}
class GlobalOptionParser extends ProviderArgsProcessor {
[@override](/user/override)
Future<void> processArgs() async {
print('GlobalOptionParser.processArgs called');
ref.read(hostArgProvider.notifier).state = argResults?['host'];
ref.read(tokenArgProvider.notifier).state = argResults?['token'];
}
}
// Branch command & related options handling
//
class BranchCommand extends ProviderCommand {
[@override](/user/override)
final name = "branch";
[@override](/user/override)
final description = "branch command";
BranchCommand() {
argParser.addOption('input', help: 'input file path');
addSubcommand(LeafCommand());
}
[@override](/user/override)
void processArgs() {
print('BranchCommand.processArgs called');
ref.read(inputArgProvider.notifier).state = argResults?['input'];
}
}
// Leaf command, related options handling & command execution
//
class LeafCommand extends ProviderCommand {
[@override](/user/override)
final name = "leaf";
[@override](/user/override)
final description = "leaf command";
LeafCommand() {
argParser.addOption('output', help: 'output file path');
}
[@override](/user/override)
void processArgs() {
print('LeafCommand.processArgs called');
ref.read(outputArgProvider.notifier).state = argResults?['output'];
}
[@override](/user/override)
void execute() {
print('LeafCommand.execute called');
ref.read(fooServiceProvider).doSomething();
}
}
// Options providers
//
final hostArgProvider = StateProvider<String?>((ref) => null);
final tokenArgProvider = StateProvider<String?>((ref) => null);
final inputArgProvider = StateProvider<String?>((ref) => null);
final outputArgProvider = StateProvider<String?>((ref) => null);
final fooServiceProvider = Provider<FooService>((ref) {
return FooService(
input: ref.watch(inputArgProvider),
output: ref.watch(outputArgProvider),
);
});
// Service
//
class FooService {
FooService({
required this.input,
required this.output,
});
final String? input;
final String? output;
Future<void> doSomething() async {
print('FooService.doSomething called');
// Do the job
}
}
更多关于Flutter依赖注入与状态管理插件args_riverpod的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter依赖注入与状态管理插件args_riverpod的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用args_riverpod
进行依赖注入与状态管理的示例代码。args_riverpod
是riverpod
状态管理库的一个扩展,它主要用于处理路由参数。不过,我们通常使用riverpod
与flutter_riverpod
来管理全局状态,并通过args_riverpod
来简化从路由参数中获取依赖的操作。
首先,确保你的pubspec.yaml
文件中已经添加了必要的依赖:
dependencies:
flutter:
sdk: flutter
flutter_hooks: ^0.18.0 # 如果你打算使用Hooks API
hooks_riverpod: ^1.0.0 # Riverpod核心库,包含provider和hooks支持
flutter_riverpod: ^1.0.0 # Riverpod的Flutter绑定
args_riverpod: ^0.1.0 # 用于处理路由参数的扩展
然后,运行flutter pub get
来安装这些依赖。
设置Riverpod
在你的应用入口文件(通常是main.dart
)中,设置Riverpod:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:args_riverpod/args_riverpod.dart';
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/detail': (context) => DetailScreen(),
},
onGenerateRoute: (settings) => generateRouteWithArgs(context, settings),
);
}
}
Route<dynamic> generateRouteWithArgs(BuildContext context, RouteSettings settings) {
// 这里是args_riverpod发挥作用的地方,它会根据路由参数创建ProviderScope
return context.read(routerProvider.notifier).generateRoute(settings);
}
定义路由Provider
接下来,定义一个Provider来处理路由:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:args_riverpod/args_riverpod.dart';
final routerProvider = RouterProvider<Map<String, dynamic>>(
(ref) {
// 这里可以定义你的路由生成逻辑,这里我们简单地返回null
return null;
},
);
使用依赖注入和状态管理
现在,让我们在屏幕组件中使用这些Provider。
HomeScreen
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class HomeScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/detail', arguments: {'id': 123});
},
child: Text('Go to Detail'),
),
),
);
}
}
DetailScreen
在DetailScreen中,我们将使用args_riverpod
提供的功能来获取路由参数:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:args_riverpod/args_riverpod.dart';
class DetailScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final args = ref.watch(routeArgsProvider);
return Scaffold(
appBar: AppBar(
title: Text('Detail Screen'),
),
body: Center(
child: Text('Detail ID: ${args?['id']}'),
),
);
}
}
在这个例子中,routeArgsProvider
是由args_riverpod
自动生成的,它允许你直接从Provider中获取路由参数。
总结
以上代码展示了如何在Flutter项目中使用args_riverpod
与riverpod
进行依赖注入和状态管理。通过这种方式,你可以轻松地在不同屏幕之间传递数据,同时保持代码的整洁和可维护性。