创建项目 在指定文件夹创建一个新的 Flutter
项目, 如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 PS D:\sources\flutter_repos> flutter create my_example_app Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source ! Creating project my_example_app... Running "flutter pub get" in my_example_app... Resolving dependencies in my_example_app... + async 2.10.0 (2.11.0 available) + boolean_selector 2.1.1 + characters 1.2.1 (1.3.0 available) + clock 1.1.1 + collection 1.17.0 (1.17.1 available) + cupertino_icons 1.0.5 + fake_async 1.3.1 + flutter 0.0.0 from sdk flutter + flutter_lints 2.0.1 + flutter_test 0.0.0 from sdk flutter + js 0.6.5 (0.6.7 available) + lints 2.0.1 + matcher 0.12.13 (0.12.15 available) + material_color_utilities 0.2.0 (0.3.0 available) + meta 1.8.0 (1.9.1 available) + path 1.8.2 (1.8.3 available) + sky_engine 0.0.99 from sdk flutter + source_span 1.9.1 + stack_trace 1.11.0 + stream_channel 2.1.1 + string_scanner 1.2.0 + term_glyph 1.2.1 + test_api 0.4.16 (0.5.0 available) + vector_math 2.1.4 Changed 24 dependencies in my_example_app! Wrote 127 files. All done ! You can find general documentation for Flutter at: https://docs.flutter.dev/ Detailed API documentation is available at: https://api.flutter.dev/ If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev In order to run your application, type : $ cd my_example_app $ flutter run Your application code is in my_example_app\lib\main.dart.
在 Visual Studio Code
中打开创建好的my_example_app
项目
添加依赖 Riverpod
有三种方式, 可以根据下图进行选择:
这里不使用 flutter_hooks
, 所以 选择flutter_riverpod
flutter_riverpod
的最新版本: https://pub.flutter-io.cn/packages/flutter_riverpod
在 pubspec.yaml
中添加引用:
1 2 3 4 5 6 7 8 9 dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 flutter_riverpod: ^2.3.2
使用基础 Provider
是 Riverpod
应用程序中最重要的部分。 Provider
是一个对象,它 封装
了一些 状态
并允许 监听
该 状态
。
要使 Provider
程序正常工作,必须在 Flutter
的 根应用程序
中添加 ProviderScope
, 代码如下所示:
1 2 3 4 5 6 7 8 9 10 void main() { runApp( const ProviderScope( child: MyApp(), ), ); }
不同类型的 Providers
对于多个不同的用例,有多种类型的 providers
。
由于所有这些 providers
都可用,有时很难理解何时使用一种类型的 provider
而不是另一种。以下表格列出了适合于不同使用场景的 provider
。
Provider
类型
Provider
创建功能
使用示例
Provider
返回任何类型
服务类/计算属性(过滤列表)
StateProvider
返回任何类型
过滤条件/简单状态对象
FutureProvider
返回任意类型的 Future
来自 API 调用的返回值
StreamProvider
返回任何类型的 Stream
来自 API 的 Stream 返回值
StateNotifierProvider
返回 StateNotifier
的子类
一个复杂的状态对象,只能通过接口改变的状态的值
ChangeNotifierProvider
返回 ChangeNotifier
的子类
需要可变性的复杂状态对象
警告: 虽然所有的 providers
都有存在的目的,但对于可扩展的应用程序来说,不建议使用 ChangeNotifierProviders
,因为它存在可变状态的问题。它存在于 flutter_riverpod
包中,以提供一个简单的从包:package:provider
,并允许一些 flutter
特定的使用情况,如与一些 Navigator 2
包的集成。
provider Provider
是所有Providers
中最基本的。它返回了一个Value
… 仅此而已。
Provider
通常用于下面的场景:
使用 Riverpod
的 Provider
需要三步就可以。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import 'package:flutter/material.dart' ;import 'package:flutter_riverpod/flutter_riverpod.dart' ;final Provider<String > helloWorldProvider = Provider((_) => 'Hello World!' );void main() { runApp( ProviderScope( child: MyApp(), ), ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Riverpod Example' , theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: ProviderExample(), ); } } class ProviderExample extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final String value = ref.watch(helloWorldProvider); return Scaffold( appBar: AppBar(title: const Text('Example' )), body: Center( child: Text(value), ), ); } }
这里储存 Hello World!
使用的是Provider
,它提供一个永远不变
的对象。不过大部分场景下状态都是可变的,下面用计数器来举例。
StateProvider StateProvider
是一个公开了修改其状态的方法的Provider
。它是StateNotifierProvider
的简化版,旨在避免为非常简单的用例编写一个StateNotifier
类。
StateProvider
的存在主要是为了允许用户对简单的变量进行修改。一个StateProvider
所维护的状态通常是下面几种。
而下面这些场景,就不适合使用StateProvider
:
定义一个全局 StateProvider
1 final StateProvider<int > counterProvider = StateProvider((ref) => 0 );
Flutter Riverpod
使用ConsumerWidget
代替StatelessWidget
。
ConsumerWidget
在使用上与StatelessWidget
相同,唯一的区别是它的构建方法
上有一个额外的参数:"ref "
对象。
1 2 3 4 5 6 7 class MyHomePage extends ConsumerWidget { const MyHomePage({super .key}); @override Widget build(BuildContext context, WidgetRef ref) {
监听及更新状态 1 2 3 4 5 final count = ref.watch(counterProvider);ref.read(counterProvider.notifier).state++;
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 import 'package:flutter/material.dart' ;import 'package:flutter_riverpod/flutter_riverpod.dart' ;final StateProvider<int > counterProvider = StateProvider((ref) => 0 );void main() { runApp( const ProviderScope( child: MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super .key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo' , theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); } } class MyHomePage extends ConsumerWidget { const MyHomePage({super .key}); @override Widget build(BuildContext context, WidgetRef ref) { final count = ref.watch(counterProvider); return Scaffold( appBar: AppBar( title: const Text('StateProvider Example' ), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:' , ), Text( '$count ' , style: Theme.of(context).textTheme.headlineMedium, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: () => ref.read(counterProvider.notifier).state++, tooltip: 'Increment' , child: const Icon(Icons.add), ), ); } }