Flutter状态恢复与依赖管理插件flutter_riverpod_restorable的使用
Flutter状态恢复与依赖管理插件flutter_riverpod_restorable的使用
特性
Riverpod 不提供简单的状态恢复方法,当应用被操作系统杀死时,状态将无法恢复。此插件提供了这样的功能。
使用方法
如何注册全局提供者以进行状态恢复
final counterProvider = RestorableProvider(
// 我们的默认值
(ref) => RestorableInt(0),
// 每个提供者都需要一个唯一的恢复ID
restorationId: 'counterProvider',
);
MaterialApp(
// 必须恢复状态
restorationScopeId: 'root',
// 必须注册全局提供者以进行恢复
builder: (context, child) => RestorableProviderRegister(
restorationId: 'app',
providers: [
// 在这里列出你的全局可恢复提供者
counterProvider,
],
child: child ?? const SizedBox.shrink(),
),
);
如何注册覆盖提供者以进行状态恢复
RestorableProviderScope(
restorationId: 'counter_page_scope',
overrides: [
// 如果你只使用被覆盖的恢复提供者,则只需在这里添加它。
counterProvider.overrideWith((ref) => RestorableInt(0)),
],
child: const CounterPage(),
)
其他信息
有关如何恢复导航的信息,请参阅示例或访问 Flutter 文档。
示例代码
以下是一个完整的示例,展示了如何使用 flutter_riverpod_restorable
插件来实现状态恢复和依赖管理。
import 'package:flutter/services.dart' show StandardMessageCodec;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_restorable/flutter_riverpod_restorable.dart';
void main() => runApp(const ProviderScope(child: MyApp()));
final materialColors = [
Colors.red,
Colors.pink,
Colors.purple,
Colors.deepPurple,
Colors.indigo,
Colors.blue,
Colors.lightBlue,
Colors.cyan,
Colors.teal,
Colors.green,
Colors.lightGreen,
Colors.lime,
Colors.yellow,
Colors.amber,
Colors.orange,
Colors.deepOrange,
Colors.brown,
Colors.grey,
Colors.blueGrey,
];
/// 我们只能恢复可以由 [StandardMessageCodec] 序列化的值。
/// 对于任何不能由 [StandardMessageCodec] 序列化的值,我们必须自己进行序列化。
/// 一种简单的方法是将其从/向JSON转换。
/// 有关更多信息,请参阅 [RestorableProperty]。
class RestorableMaterialColor extends RestorableValue<MaterialColor> {
RestorableMaterialColor(this._defaultValue);
final MaterialColor _defaultValue;
[@override](/user/override)
MaterialColor createDefaultValue() => _defaultValue;
[@override](/user/override)
void didUpdateValue(MaterialColor? oldValue) => notifyListeners();
[@override](/user/override)
MaterialColor fromPrimitives(Object? data) {
final value = (data as List).cast<int>();
return MaterialColor(value[0], {
50: Color(value[1]),
100: Color(value[2]),
200: Color(value[3]),
300: Color(value[4]),
400: Color(value[5]),
500: Color(value[6]),
600: Color(value[7]),
700: Color(value[8]),
800: Color(value[9]),
900: Color(value[10]),
});
}
[@override](/user/override)
Object? toPrimitives() => [
value.value,
value.shade50.value,
value.shade100.value,
value.shade200.value,
value.shade300.value,
value.shade400.value,
value.shade500.value,
value.shade600.value,
value.shade700.value,
value.shade800.value,
value.shade900.value,
];
}
/// 每个 [RestorableProvider] 都必须有一个唯一的 [RestorableProvider.restorationId]
final primaryMaterialColorProvider =
RestorableProvider<RestorableMaterialColor>(
(ref) => RestorableMaterialColor(Colors.blue),
restorationId: 'primaryMaterialColorProvider',
);
final counterProvider = RestorableProvider<RestorableInt>(
(ref) => throw UnimplementedError(),
restorationId: 'counterProvider',
);
class MyApp extends ConsumerWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
/// 必须恢复状态
restorationScopeId: 'root',
/// 必须注册全局提供者以进行恢复
builder: (context, child) => RestorableProviderRegister(
restorationId: 'app',
providers: [
primaryMaterialColorProvider,
],
child: child ?? const SizedBox.shrink(),
),
home: const HomePage(),
);
}
}
class HomePage extends ConsumerWidget {
const HomePage({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context, WidgetRef ref) {
final color = ref.watch(primaryMaterialColorProvider).value;
return Theme(
data: ThemeData(primarySwatch: color),
child: Scaffold(
appBar: AppBar(
title: const Text('Home Page'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
child: const Text("Open counter screen"),
onPressed: () => _onCounter(context),
),
ElevatedButton(
child: const Text("Random color"),
onPressed: () {
final color = ref.read(primaryMaterialColorProvider);
color.value = (materialColors..shuffle()).first;
},
),
],
),
),
),
);
}
/// 使用可恢复的导航方法来记住当前导航状态。
/// 传递的任何参数都必须由 [StandardMessageCodec] 序列化。
String _onCounter(BuildContext context) {
return Navigator.of(context).restorablePush(_buildRoute, arguments: 0);
}
/// 路由必须静态才能被恢复。
static Route<void> _buildRoute(BuildContext context, Object? params) {
return MaterialPageRoute(
builder: (BuildContext context) {
/// 如果你想覆盖一个 [RestorableProvider],你必须使用 [RestorableProviderScope]。
return RestorableProviderScope(
restorationId: 'counter_page_scope',
overrides: [
counterProvider.overrideWith((ref) => RestorableInt(params as int)),
],
child: const CounterPage(),
);
},
);
}
}
class CounterPage extends ConsumerWidget {
const CounterPage({Key? key}) : super(key: key);
void _incrementCounter(WidgetRef ref) {
final counter = ref.read(counterProvider);
counter.value++;
}
[@override](/user/override)
Widget build(BuildContext context, WidgetRef ref) {
final color = ref.watch(primaryMaterialColorProvider).value;
final counter = ref.watch(counterProvider);
return Theme(
data: ThemeData(primarySwatch: color),
child: Scaffold(
appBar: AppBar(
title: const Text("Counter"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text(
'${counter.value}',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _incrementCounter(ref),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
),
);
}
}
更多关于Flutter状态恢复与依赖管理插件flutter_riverpod_restorable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter状态恢复与依赖管理插件flutter_riverpod_restorable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter应用中使用flutter_riverpod_restorable
插件进行状态恢复与依赖管理的代码示例。这个插件允许你在应用重新启动时恢复Riverpod的状态。
首先,确保你已经在pubspec.yaml
文件中添加了必要的依赖:
dependencies:
flutter:
sdk: flutter
flutter_hooks: ^0.18.0 # 如果你使用Flutter Hooks
flutter_riverpod: ^1.0.0 # 请根据最新版本调整
flutter_riverpod_restorable: ^0.2.0 # 请根据最新版本调整
然后,运行flutter pub get
来安装这些依赖。
接下来,让我们创建一个简单的Flutter应用,演示如何使用flutter_riverpod_restorable
。
主应用文件 (main.dart)
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_restorable/flutter_riverpod_restorable.dart';
void main() {
runApp(
ProviderScope(
overrides: [
restorableStateProvider.overrideWithValue(
RestorableState(
storage: FlutterStorage(), // 使用Flutter的本地存储
),
),
],
child: MyApp(),
),
);
}
class MyApp extends HookWidget {
@override
Widget build(BuildContext context) {
final counterProvider = useRestorableProvider((ref) => 0);
final increment = useStateProvider((ref) => () {
ref.value = (ref.value ?? 0) + 1;
});
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Riverpod Restorable Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'${counterProvider.state}',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => increment.read().call(),
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
);
}
}
解释
-
ProviderScope: 在
main
函数中,我们使用ProviderScope
来包裹整个应用,并覆盖restorableStateProvider
,使用FlutterStorage
进行本地存储。 -
useRestorableProvider: 我们使用
useRestorableProvider
来创建一个可恢复的计数器状态。这个状态在应用重新启动时会从存储中恢复。 -
useStateProvider: 我们使用
useStateProvider
来创建一个增加计数器的函数。这个函数通过修改ref.value
来增加计数器的值。 -
UI部分: 在UI中,我们显示当前的计数器值,并添加一个浮动按钮来增加计数器的值。
这个示例展示了如何使用flutter_riverpod_restorable
插件来恢复应用的状态。你可以根据需要扩展这个示例,添加更多的状态管理逻辑和复杂的UI。