在这里插入图片描述
在这里插入图片描述

作者:付文龙(红目香薰)
仓库地址https://gitcode.com/feng8403000/FlutterfromBeginnertoAdvancedForHarmonyOS.git
联系邮箱:372699828@qq.com

引言

Riverpod作为新一代状态管理方案,提供了丰富的高级特性和技巧。掌握这些高级用法可以帮助开发者构建更复杂、更高效的Flutter应用。本文将深入探讨Riverpod的高级用法,包括ref.listen、autoDispose、Family的高级用法、Provider观察者、错误处理等,帮助开发者在鸿蒙平台开发Flutter应用时充分发挥Riverpod的潜力。

ref.listen监听状态变化

基本用法

class CartWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // 监听购物车变化
    ref.listen(cartProvider, (previous, next) {
      if (next.length > (previous?.length ?? 0)) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text("商品已添加到购物车")),
        );
      }
    });
    
    final cart = ref.watch(cartProvider);
    return Text("购物车商品数: ${cart.length}");
  }
}

监听部分状态

class UserWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // 只监听用户名变化
    ref.listen(
      userProvider.select((user) => user?.name),
      (previousName, currentName) {
        if (previousName != currentName) {
          print("用户名变化: $previousName -> $currentName");
        }
      },
    );
    
    final user = ref.watch(userProvider);
    return Text(user?.name ?? "未登录");
  }
}

监听异步状态

class DataWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    ref.listen<AsyncValue<List<Post>>>(postsProvider, (previous, next) {
      next.whenData((posts) {
        print("帖子加载完成: ${posts.length}条");
      });
      
      next.whenError((error, stack) {
        print("加载失败: $error");
      });
    });
    
    final posts = ref.watch(postsProvider);
    return posts.when(
      data: (posts) => ListView.builder(
        itemCount: posts.length,
        itemBuilder: (context, index) => ListTile(title: Text(posts[index].title)),
      ),
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) => Text("错误: $error"),
    );
  }
}

autoDispose自动清理

基本用法

// 自动销毁,节省内存
final userProvider = FutureProvider.autoDispose<User>((ref) async {
  final api = ref.read(apiProvider);
  return await api.getUser();
});

class UserPage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userProvider);
    return user.when(
      data: (user) => Text(user.name),
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) => Text("$error"),
    );
  }
}

keepAlive保持活跃

// 需要保持活跃的Provider
final userProvider = FutureProvider.autoDispose<User>((ref) async {
  ref.keepAlive(); // 保持活跃,不自动销毁
  
  final api = ref.read(apiProvider);
  return await api.getUser();
});

智能keepAlive

final userProvider = FutureProvider.autoDispose<User>((ref) async {
  // 当至少有一个监听者时保持活跃
  final link = ref.keepAlive();
  
  // 监听是否有活跃的监听者
  ref.listenSelf((previous, next) {
    if (next.hasValue) {
      link.close(); // 有值后关闭,允许自动销毁
    }
  });
  
  final api = ref.read(apiProvider);
  return await api.getUser();
});

Family高级用法

基本参数化

final userProvider = FutureProvider.family<User, String>((ref, userId) async {
  final api = ref.read(apiProvider);
  return await api.getUser(userId);
});

class UserProfilePage extends ConsumerWidget {
  final String userId;
  
  const UserProfilePage({super.key, required this.userId});
  
  
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userProvider(userId));
    
    return user.when(
      data: (user) => Text(user.name),
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) => Text("$error"),
    );
  }
}

组合多个参数

final searchProvider = FutureProvider.family<List<Product>, ({String query, int page})>(
  (ref, params) async {
    final api = ref.read(apiProvider);
    return await api.search(params.query, params.page);
  },
);

class SearchPage extends ConsumerWidget {
  final String query;
  
  const SearchPage({super.key, required this.query});
  
  
  Widget build(BuildContext context, WidgetRef ref) {
    final products = ref.watch(searchProvider((query: query, page: 1)));
    
    return products.when(
      data: (products) => ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) => ListTile(title: Text(products[index].name)),
      ),
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) => Text("$error"),
    );
  }
}

autoDispose与Family结合

final userProvider = FutureProvider.autoDispose.family<User, String>((ref, userId) async {
  final api = ref.read(apiProvider);
  return await api.getUser(userId);
});

// 使用
ref.watch(userProvider("1")); // 当不再使用时自动销毁

Provider观察者

自定义观察者

class ProviderLogger extends ProviderObserver {
  
  void didUpdateProvider(
    ProviderBase provider,
    Object? previousValue,
    Object? newValue,
    ProviderContainer container,
  ) {
    print("""
      Provider更新:
        Provider: ${provider.name ?? provider.runtimeType}
        旧值: $previousValue
        新值: $newValue
    """);
  }
  
  
  void didDisposeProvider(ProviderBase provider, ProviderContainer container) {
    print("Provider销毁: ${provider.name ?? provider.runtimeType}");
  }
  
  
  void providerDidFail(
    ProviderBase provider,
    Object error,
    StackTrace stackTrace,
    ProviderContainer container,
  ) {
    print("""
      Provider错误:
        Provider: ${provider.name ?? provider.runtimeType}
        错误: $error
        堆栈: $stackTrace
    """);
  }
}

void main() {
  runApp(
    ProviderScope(
      observers: [ProviderLogger()],
      child: MyApp(),
    ),
  );
}

性能监控

class PerformanceObserver extends ProviderObserver {
  final Map<String, Stopwatch> _timers = {};
  
  
  void didUpdateProvider(
    ProviderBase provider,
    Object? previousValue,
    Object? newValue,
    ProviderContainer container,
  ) {
    final name = provider.name ?? provider.runtimeType.toString();
    
    if (newValue is AsyncLoading) {
      _timers[name] = Stopwatch()..start();
    } else if (newValue is AsyncData) {
      final timer = _timers.remove(name);
      if (timer != null) {
        timer.stop();
        print("Provider $name 加载耗时: ${timer.elapsedMilliseconds}ms");
      }
    }
  }
}

错误处理

全局错误捕获

void main() {
  runApp(
    ProviderScope(
      observers: [ErrorObserver()],
      child: MyApp(),
    ),
  );
}

class ErrorObserver extends ProviderObserver {
  
  void providerDidFail(
    ProviderBase provider,
    Object error,
    StackTrace stackTrace,
    ProviderContainer container,
  ) {
    // 上报错误到日志服务
    print("Provider错误: $error");
    // Sentry.captureException(error, stackTrace: stackTrace);
  }
}

局部错误处理

final userProvider = FutureProvider<User>((ref) async {
  final api = ref.read(apiProvider);
  
  try {
    return await api.getUser();
  } catch (e) {
    // 转换错误类型
    throw UserLoadException("加载用户失败", e);
  }
});

class UserLoadException implements Exception {
  final String message;
  final Object? cause;
  
  UserLoadException(this.message, [this.cause]);
  
  
  String toString() => "UserLoadException: $message";
}

class UserWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userProvider);
    
    return user.when(
      data: (user) => Text(user.name),
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) {
        if (error is UserLoadException) {
          return Column(
            children: [
              Text(error.message),
              ElevatedButton(
                onPressed: () => ref.invalidate(userProvider),
                child: const Text("重试"),
              ),
            ],
          );
        }
        return Text("未知错误: $error");
      },
    );
  }
}

核心高级技巧示例

示例1:复杂状态联动

final searchQueryProvider = StateProvider<String>((ref) => "");

final searchResultsProvider = FutureProvider<List<Product>>((ref) async {
  final query = ref.watch(searchQueryProvider);
  
  if (query.isEmpty) {
    return [];
  }
  
  final api = ref.read(apiProvider);
  return await api.search(query);
});

final filteredResultsProvider = Provider<List<Product>>((ref) {
  final results = ref.watch(searchResultsProvider);
  final filter = ref.watch(filterProvider);
  
  return results.when(
    data: (products) => products.where(filter.apply).toList(),
    loading: () => [],
    error: (_, __) => [],
  );
});

class SearchFilter {
  final double? minPrice;
  final double? maxPrice;
  final String? category;
  
  SearchFilter({this.minPrice, this.maxPrice, this.category});
  
  bool apply(Product product) {
    if (minPrice != null && product.price < minPrice!) return false;
    if (maxPrice != null && product.price > maxPrice!) return false;
    if (category != null && product.category != category!) return false;
    return true;
  }
}

final filterProvider = StateProvider<SearchFilter>((ref) => SearchFilter());

class SearchPage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final query = ref.watch(searchQueryProvider);
    final results = ref.watch(filteredResultsProvider);
    
    return Column(
      children: [
        TextField(
          onChanged: (value) => ref.read(searchQueryProvider.notifier).state = value,
          decoration: const InputDecoration(labelText: "搜索"),
        ),
        Expanded(
          child: ListView.builder(
            itemCount: results.length,
            itemBuilder: (context, index) {
              final product = results[index];
              return ListTile(title: Text(product.name));
            },
          ),
        ),
      ],
    );
  }
}

示例2:事件总线模式

final eventBusProvider = Provider<EventBus>((ref) => EventBus());

class EventBus {
  final _events = StreamController<AppEvent>.broadcast();
  
  Stream<AppEvent> get events => _events.stream;
  
  void emit(AppEvent event) {
    _events.add(event);
  }
  
  void dispose() {
    _events.close();
  }
}

abstract class AppEvent {}

class CartUpdatedEvent extends AppEvent {
  final int itemCount;
  
  CartUpdatedEvent(this.itemCount);
}

class NotificationEvent extends AppEvent {
  final String message;
  
  NotificationEvent(this.message);
}

// 使用事件总线
class CartNotifier extends StateNotifier<List<CartItem>> {
  CartNotifier(this.ref) : super([]);
  
  final Ref ref;
  
  void addItem(CartItem item) {
    state = [...state, item];
    
    // 发送事件
    ref.read(eventBusProvider).emit(CartUpdatedEvent(state.length));
  }
}

// 监听事件
class CartBadgeWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // 监听事件总线
    ref.listen<AsyncValue<AppEvent>>(
      eventBusProvider.select((bus) => bus.events),
      (previous, next) {
        next.whenData((event) {
          if (event is CartUpdatedEvent) {
            print("购物车更新: ${event.itemCount}");
          }
        });
      },
    );
    
    final itemCount = ref.watch(cartItemCountProvider);
    return Badge(label: Text("$itemCount"));
  }
}

示例3:防抖搜索

final searchQueryProvider = StateProvider<String>((ref) => "");

final debouncedSearchProvider = FutureProvider<List<Product>>((ref) async {
  final query = ref.watch(searchQueryProvider);
  
  if (query.isEmpty) {
    return [];
  }
  
  // 防抖延迟
  await Future.delayed(const Duration(milliseconds: 300));
  
  // 如果查询在等待期间改变了,取消请求
  final currentQuery = ref.watch(searchQueryProvider);
  if (currentQuery != query) {
    throw Exception("查询已改变");
  }
  
  final api = ref.read(apiProvider);
  return await api.search(query);
});

class SearchPage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final results = ref.watch(debouncedSearchProvider);
    
    return Column(
      children: [
        TextField(
          onChanged: (value) => ref.read(searchQueryProvider.notifier).state = value,
          decoration: const InputDecoration(labelText: "搜索"),
        ),
        results.when(
          data: (products) => Expanded(
            child: ListView.builder(
              itemCount: products.length,
              itemBuilder: (context, index) => ListTile(title: Text(products[index].name)),
            ),
          ),
          loading: () => const Expanded(child: Center(child: CircularProgressIndicator())),
          error: (error, stack) => const Expanded(child: Center(child: Text(""))),
        ),
      ],
    );
  }
}

示例4:批量状态更新

class BatchUpdateNotifier extends StateNotifier<Map<String, dynamic>> {
  BatchUpdateNotifier() : super({});
  
  void updateMultiple({
    String? name,
    int? count,
    bool? enabled,
  }) {
    state = {
      ...state,
      if (name != null) "name": name,
      if (count != null) "count": count,
      if (enabled != null) "enabled": enabled,
    };
  }
  
  void reset() {
    state = {};
  }
}

final batchProvider = StateNotifierProvider<BatchUpdateNotifier, Map<String, dynamic>>((ref) {
  return BatchUpdateNotifier();
});

class BatchUpdateWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final state = ref.watch(batchProvider);
    final notifier = ref.read(batchProvider.notifier);
    
    return Column(
      children: [
        Text("名称: ${state["name"] ?? "未设置"}"),
        Text("数量: ${state["count"] ?? 0}"),
        Text("启用: ${state["enabled"] ?? false}"),
        ElevatedButton(
          onPressed: () => notifier.updateMultiple(
            name: "新产品",
            count: 10,
            enabled: true,
          ),
          child: const Text("批量更新"),
        ),
      ],
    );
  }
}

示例5:条件Provider

final useMockDataProvider = StateProvider<bool>((ref) => false);

final dataProvider = Provider<DataSource>((ref) {
  final useMock = ref.watch(useMockDataProvider);
  
  if (useMock) {
    return MockDataSource();
  }
  return RealDataSource();
});

abstract class DataSource {
  Future<List<Product>> getProducts();
}

class RealDataSource implements DataSource {
  
  Future<List<Product>> getProducts() async {
    await Future.delayed(const Duration(seconds: 1));
    return [Product(id: "1", name: "真实商品", price: 100)];
  }
}

class MockDataSource implements DataSource {
  
  Future<List<Product>> getProducts() async {
    await Future.delayed(const Duration(milliseconds: 100));
    return [Product(id: "1", name: "Mock商品", price: 50)];
  }
}

final productsProvider = FutureProvider<List<Product>>((ref) async {
  final dataSource = ref.watch(dataProvider);
  return await dataSource.getProducts();
});

class ProductPage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final useMock = ref.watch(useMockDataProvider);
    final products = ref.watch(productsProvider);
    
    return Column(
      children: [
        Switch(
          value: useMock,
          onChanged: (value) => ref.read(useMockDataProvider.notifier).state = value,
        ),
        const Text("使用Mock数据"),
        Expanded(
          child: products.when(
            data: (products) => ListView.builder(
              itemCount: products.length,
              itemBuilder: (context, index) => ListTile(title: Text(products[index].name)),
            ),
            loading: () => const Center(child: CircularProgressIndicator()),
            error: (error, stack) => Text("错误: $error"),
          ),
        ),
      ],
    );
  }
}

示例6:分页加载

final currentPageProvider = StateProvider<int>((ref) => 1);

final productsProvider = FutureProvider<List<Product>>((ref) async {
  final page = ref.watch(currentPageProvider);
  final api = ref.read(apiProvider);
  return await api.getProducts(page);
});

final allProductsProvider = StateNotifierProvider<ProductsNotifier, List<Product>>((ref) {
  return ProductsNotifier(ref);
});

class ProductsNotifier extends StateNotifier<List<Product>> {
  ProductsNotifier(this.ref) : super([]);
  
  final Ref ref;
  bool _isLoading = false;
  int _currentPage = 1;
  
  Future<void> loadMore() async {
    if (_isLoading) return;
    
    _isLoading = true;
    _currentPage++;
    
    ref.read(currentPageProvider.notifier).state = _currentPage;
    
    try {
      final newProducts = await ref.read(productsProvider.future);
      state = [...state, ...newProducts];
    } catch (_) {
      _currentPage--;
    } finally {
      _isLoading = false;
    }
  }
  
  Future<void> refresh() async {
    _currentPage = 1;
    ref.read(currentPageProvider.notifier).state = 1;
    
    final newProducts = await ref.read(productsProvider.future);
    state = newProducts;
  }
}

class ProductListPage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final products = ref.watch(allProductsProvider);
    final notifier = ref.read(allProductsProvider.notifier);
    
    return RefreshIndicator(
      onRefresh: () => notifier.refresh(),
      child: ListView.builder(
        itemCount: products.length + 1,
        itemBuilder: (context, index) {
          if (index == products.length) {
            return const Center(child: CircularProgressIndicator());
          }
          return ListTile(title: Text(products[index].name));
        },
        onEndReached: () => notifier.loadMore(),
        onEndReachedThreshold: 200,
      ),
    );
  }
}

性能优化技巧

使用select减少重建

class UserWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // 只监听用户名,其他字段变化不会触发重建
    final userName = ref.watch(userProvider.select((user) => user?.name ?? ""));
    
    return Text(userName);
  }
}

使用watchOnly

class UserWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // 只监听必要的字段
    final (name, email) = ref.watch(
      userProvider.select((user) => (user?.name ?? "", user?.email ?? "")),
    );
    
    return Column(
      children: [Text(name), Text(email)],
    );
  }
}

避免在build中创建对象

// 错误
class MyWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final style = TextStyle(fontSize: 16); // 每次build都会创建新对象
    return Text("Hello", style: style);
  }
}

// 正确
class MyWidget extends ConsumerWidget {
  static const _style = TextStyle(fontSize: 16); // 复用
  
  
  Widget build(BuildContext context, WidgetRef ref) {
    return Text("Hello", style: _style);
  }
}

使用const构造函数

class MyWidget extends ConsumerWidget {
  const MyWidget({super.key}); // const构造函数
  
  
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(countProvider);
    return const Text("Hello"); // const子Widget不会重建
  }
}

鸿蒙平台特别考虑

平台特定Provider

final platformProvider = Provider<PlatformService>((ref) {
  if (Platform.isAndroid) {
    return AndroidPlatformService();
  }
  return DefaultPlatformService();
});

abstract class PlatformService {
  Future<void> showNotification(String message);
}

class AndroidPlatformService implements PlatformService {
  
  Future<void> showNotification(String message) async {
    // Android实现
  }
}

class DefaultPlatformService implements PlatformService {
  
  Future<void> showNotification(String message) async {
    // 默认实现
  }
}

权限状态管理

final permissionStatusProvider = StateNotifierProvider<PermissionNotifier, Map<Permission, bool>>((ref) {
  return PermissionNotifier(ref);
});

enum Permission { storage, camera, location }

class PermissionNotifier extends StateNotifier<Map<Permission, bool>> {
  PermissionNotifier(this.ref) : super({});
  
  final Ref ref;
  
  Future<bool> request(Permission permission) async {
    // 鸿蒙平台权限请求
    final granted = true; // 实际实现
    state = {...state, permission: granted};
    return granted;
  }
  
  bool has(Permission permission) {
    return state[permission] ?? false;
  }
}

最佳实践

1. Provider命名规范

// 基础Provider
final appNameProvider = Provider<String>((ref) => "MyApp");

// 状态Provider
final countProvider = StateProvider<int>((ref) => 0);

// StateNotifierProvider
final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>((ref) => CartNotifier());

// FutureProvider
final userProvider = FutureProvider<User>((ref) async => await fetchUser());

// StreamProvider
final messagesProvider = StreamProvider<Message>((ref) => messageStream);

// Family
final userByIdProvider = FutureProvider.family<User, String>((ref, id) async => await fetchUser(id));

2. 状态分层

// 服务层
final apiProvider = Provider<ApiService>((ref) => ApiServiceImpl());

// 数据层
final userProvider = FutureProvider<User>((ref) async {
  final api = ref.read(apiProvider);
  return await api.getUser();
});

// 业务层
final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>((ref) => CartNotifier());

// UI层
final cartTotalProvider = Provider<double>((ref) {
  final cart = ref.watch(cartProvider);
  return cart.fold(0, (sum, item) => sum + item.price);
});

3. 使用扩展方法

extension WidgetRefExtension on WidgetRef {
  void showSnackBar(BuildContext context, String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }
  
  Future<void> refreshData<T>(FutureProvider<T> provider) async {
    invalidate(provider);
    await read(provider.future);
  }
}

// 使用
class MyWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    ref.showSnackBar(context, "Hello");
    return Container();
  }
}

4. 组合Provider

final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) => AuthNotifier(ref));

final userProvider = FutureProvider<User>((ref) async {
  final authState = ref.watch(authProvider);
  
  if (authState.status != AuthStatus.authenticated) {
    throw Exception("未登录");
  }
  
  final api = ref.read(apiProvider);
  return await api.getUser(authState.user!.id);
});

总结

Riverpod的高级用法和技巧为开发者提供了强大的工具来构建复杂的Flutter应用:

  1. ref.listen:监听状态变化,执行副作用操作。
  2. autoDispose:自动清理资源,节省内存。
  3. Family:参数化Provider,支持动态数据获取。
  4. Provider观察者:监控Provider状态变化,实现日志和错误追踪。
  5. 错误处理:全局和局部错误捕获,提供良好的用户体验。
  6. 性能优化:使用select、watchOnly、const构造函数等减少不必要的重建。

在鸿蒙平台开发Flutter应用时,这些高级技巧将帮助开发者构建更高效、更稳定的应用,充分发挥Riverpod的潜力。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐