Flutter中如何将Stream转为Listenable供go_router的refreshListenable使用
实现方案
1. 编写 Stream 转 Listenable 的适配类
因为 GoRouter 的 refreshListenable 参数要求传入 Listenable 类型,我们可以基于 ChangeNotifier 做一层适配,监听鉴权流的变化时自动发送通知:
import 'package:flutter/foundation.dart'; class AuthStateListenable extends ChangeNotifier { late final StreamSubscription _authSubscription; AuthStateListenable(Stream<bool> authStateStream) { // 每次鉴权状态变化时触发通知,让GoRouter执行重定向逻辑 _authSubscription = authStateStream.listen((_) => notifyListeners()); } @override void dispose() { _authSubscription.cancel(); super.dispose(); } }
2. 新增对应Provider
我们新增两个Provider,分别暴露可监听的鉴权状态对象,以及直接可读的登录状态值:
// 提供给GoRouter的refreshListenable final authStateListenableProvider = Provider.autoDispose<AuthStateListenable>((ref) { final authService = ref.watch(authServiceProvider); final listenable = AuthStateListenable(authService.isLoggedIn); // 自动销毁资源 ref.onDispose(() => listenable.dispose()); return listenable; }); // 直接提供登录状态,方便在重定向逻辑中读取 final isLoggedInProvider = StreamProvider.autoDispose<bool>((ref) { final authService = ref.watch(authServiceProvider); return authService.isLoggedIn; });
3. 配置GoRouter
推荐在main函数中初始化Provider容器,再完成路由的配置,避免跨上下文读取Provider的问题:
void main() { // 初始化Riverpod容器 final providerContainer = ProviderContainer(); // 读取鉴权监听对象 final authListenable = providerContainer.read(authStateListenableProvider); final router = GoRouter( refreshListenable: authListenable, redirect: (context, state) { // 读取当前登录状态 final isLoggedIn = providerContainer.read(isLoggedInProvider).valueOrNull ?? false; final isOnAuthRoute = state.matchedLocation == '/signin'; // 未登录且不在登录页则跳转到登录页 if (!isLoggedIn && !isOnAuthRoute) return '/signin'; // 已登录且在登录页则跳转到首页 if (isLoggedIn && isOnAuthRoute) return '/'; return null; }, // 其余路由配置省略 ); runApp( ProviderScope( parent: providerContainer, child: MyApp(router: router), ), ); }
内容的提问来源于stack exchange,提问作者Florian Leeser
相关产品推荐
相关产品推荐

