Riverpod 是 Flutter 中强大的状态管理库,提供多种 Provider 类型以适应不同场景。以下是主要使用方式及特点,附带详细代码案例:
1. Provider(基础只读值)
特点:
- 提供不可变数据或服务对象(如工具类、配置信息)
- 不触发 UI 重建,轻量高效
代码案例:
scala
// 定义日志服务 Provider
final loggerProvider = Provider<Logger>((ref) {
return Logger(); // 返回一个日志工具实例
});
// 使用
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final logger = ref.read(loggerProvider); // 读取 Provider
logger.log("Hello Riverpod!");
return Text("Check console for logs");
}
}
注释 :Provider
适合全局共享不变对象,如工具类4。
2. StateProvider(简单可变状态)
特点:
- 管理简单可变状态(如计数器、开关状态)
- 自动触发 UI 重建
代码案例:
scala
// 定义计数器状态
final counterProvider = StateProvider<int>((ref) => 0);
// 使用
class CounterPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider); // 监听状态变化
return ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++, // 修改状态
child: Text("Count: $count"),
);
}
}
注释 :StateProvider
适合局部简单状态,无需复杂逻辑24。
3. FutureProvider(异步数据)
特点:
- 处理异步操作(如网络请求)
- 自动管理加载、错误、成功状态
代码案例:
scala
// 定义异步数据 Provider
final userDataProvider = FutureProvider<User>((ref) async {
final response = await http.get('https://api.example.com/user');
return User.fromJson(response.data);
});
// 使用
class UserProfile extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userDataProvider);
return userAsync.when(
loading: () => CircularProgressIndicator(),
error: (err, _) => Text("Error: $err"),
data: (user) => Text("Username: ${user.name}"),
);
}
}
注释 :FutureProvider
封装异步操作,简化状态处理6。
4. StateNotifierProvider(复杂业务逻辑)
特点:
- 分离状态和业务逻辑,适合中大型项目
- 高可测试性和可维护性
代码案例:
scala
// 定义业务逻辑类
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
// 关联 Provider
final counterNotifierProvider = StateNotifierProvider<CounterNotifier, int>(
(ref) => CounterNotifier(),
);
// 使用
class AdvancedCounter extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterNotifierProvider);
return Row(
children: [
IconButton(onPressed: () => ref.read(counterNotifierProvider.notifier).decrement(), icon: Icon(Icons.remove)),
Text("$count"),
IconButton(onPressed: () => ref.read(counterNotifierProvider.notifier).increment(), icon: Icon(Icons.add)),
],
);
}
}
一个复杂且全面的案例
less
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 1. 定义用户数据模型
class User {
final String id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
// 重写toString方法,便于调试
@override
String toString() => 'User(id: $id, name: $name, email: $email)';
}
// 2. 定义认证状态模型
class AuthState {
final User? user; // 当前用户,null表示未登录
final bool isLoading; // 是否正在加载(如登录中)
final String? error; // 错误信息
AuthState({
this.user,
this.isLoading = false,
this.error,
});
// 是否已登录的便捷getter
bool get isLoggedIn => user != null;
// 复制方法,用于不可变更新
AuthState copyWith({
User? user,
bool? isLoading,
String? error,
}) {
return AuthState(
user: user ?? this.user,
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
);
}
}
// 3. 创建认证状态管理Notifier
class AuthNotifier extends StateNotifier<AuthState> {
// 初始化状态为未登录
AuthNotifier() : super(AuthState());
// 模拟登录方法
Future<void> login(String email, String password) async {
// 开始加载,清空错误
state = state.copyWith(isLoading: true, error: null);
try {
// 模拟网络请求延迟
await Future.delayed(Duration(seconds: 2));
// 模拟登录验证
if (email == 'admin@example.com' && password == '123456') {
// 登录成功,创建用户对象
final user = User(
id: '1',
name: '管理员',
email: email,
);
// 更新状态为已登录
state = state.copyWith(user: user, isLoading: false);
} else {
// 登录失败
throw Exception('邮箱或密码错误');
}
} catch (e) {
// 登录失败,设置错误信息
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
}
}
// 退出登录方法
void logout() {
state = state.copyWith(user: null, error: null);
}
// 清除错误信息
void clearError() {
state = state.copyWith(error: null);
}
}
// 4. 创建认证状态Provider
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
return AuthNotifier();
});
// 5. 创建衍生Provider(基于authProvider)
// 当前用户Provider
final currentUserProvider = Provider<User?>((ref) {
return ref.watch(authProvider).user;
});
// 登录状态Provider
final isLoggedInProvider = Provider<bool>((ref) {
return ref.watch(authProvider).isLoggedIn;
});
void main() {
runApp(
ProviderScope(
child: AuthExampleApp(),
),
);
}
class AuthExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Riverpod认证示例',
home: AuthWrapper(), // 使用包装器决定显示哪个页面
);
}
}
// 6. 认证包装器:根据登录状态显示不同页面
class AuthWrapper extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 监听登录状态
final isLoggedIn = ref.watch(isLoggedInProvider);
// 根据登录状态返回不同页面
return isLoggedIn ? HomeScreen() : LoginScreen();
}
}
class LoginScreen extends ConsumerStatefulWidget {
@override
ConsumerState<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends ConsumerState<LoginScreen> {
final _emailController = TextEditingController(text: 'admin@example.com');
final _passwordController = TextEditingController(text: '123456');
@override
Widget build(BuildContext context) {
// 监听认证状态
final authState = ref.watch(authProvider);
return Scaffold(
appBar: AppBar(title: Text('登录')),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _emailController,
decoration: InputDecoration(
labelText: '邮箱',
border: OutlineInputBorder(),
),
),
SizedBox(height: 16),
TextField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(
labelText: '密码',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
// 登录按钮
if (authState.isLoading)
CircularProgressIndicator()
else
ElevatedButton(
onPressed: _login,
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 50),
),
child: Text('登录'),
),
SizedBox(height: 16),
// 错误信息显示
if (authState.error != null)
Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.red[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.red),
),
child: Row(
children: [
Icon(Icons.error, color: Colors.red),
SizedBox(width: 8),
Expanded(
child: Text(
authState.error!,
style: TextStyle(color: Colors.red),
),
),
IconButton(
icon: Icon(Icons.close),
onPressed: () {
ref.read(authProvider.notifier).clearError();
},
),
],
),
),
],
),
),
);
}
void _login() {
final email = _emailController.text.trim();
final password = _passwordController.text.trim();
if (email.isEmpty || password.isEmpty) {
// 可以在这里添加表单验证
return;
}
// 调用登录方法
ref.read(authProvider.notifier).login(email, password);
}
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
}
class HomeScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 获取当前用户信息
final user = ref.watch(currentUserProvider);
return Scaffold(
appBar: AppBar(
title: Text('首页'),
actions: [
IconButton(
icon: Icon(Icons.logout),
onPressed: () {
// 退出登录
ref.read(authProvider.notifier).logout();
},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.check_circle, color: Colors.green, size: 64),
SizedBox(height: 16),
Text(
'登录成功!',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(height: 16),
Text('欢迎回来,${user?.name}'),
Text('邮箱: ${user?.email}'),
],
),
),
);
}
}
注释 :StateNotifierProvider
适合封装复杂业务逻辑4。
5. StreamProvider(流式数据)
特点:
- 处理实时数据流(如 WebSocket、Firebase)
- 自动订阅和取消订阅
代码案例:
scala
// 定义实时数据流
final messageStreamProvider = StreamProvider<String>((ref) {
return Stream.periodic(Duration(seconds: 1), (i) => "Message $i");
});
// 使用
class StreamDemo extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final stream = ref.watch(messageStreamProvider);
return stream.when(
data: (msg) => Text("Real-time: $msg"),
loading: () => Text("Connecting..."),
error: (err, _) => Text("Error: $err"),
);
}
}
注释 :StreamProvider
适用于实时数据更新场景3。
6. .autoDispose 修饰符(自动释放)
特点:
- 自动释放不再使用的状态,避免内存泄漏
- 适用于临时页面或弹窗状态
代码案例:
dart
// 定义自动释放的 Provider
final tempCounterProvider = StateProvider.autoDispose<int>((ref) => 0);
// 使用(与普通 StateProvider 相同)
注释 :通过 .autoDispose
修饰符实现状态自动清理5。
7. .family 修饰符(参数化 Provider)
特点:
- 根据外部参数创建唯一 Provider
- 适合分页数据、动态 ID 查询
代码案例:
rust
// 定义带参数的 Provider
final userDetailProvider = FutureProvider.family<User, String>((ref, userId) async {
return fetchUserById(userId); // 根据 ID 获取用户
});
// 使用
ref.watch(userDetailProvider("123")); // 传入参数 "123"
注释 :.family
支持动态生成 Provider 实例5。
总结对比
Provider 类型 | 适用场景 | 是否可变 | 异步支持 |
---|---|---|---|
Provider |
只读服务/工具类 | 否 | 否 |
StateProvider |
简单可变状态 | 是 | 否 |
FutureProvider |
异步数据(单次) | 否 | 是 |
StreamProvider |
实时数据流 | 否 | 是 |
StateNotifierProvider |
复杂业务逻辑 | 是 | 可选 |
通过组合这些 Provider 类型,可以灵活应对 Flutter 应用的各种状态管理需求。