Flutter中RetryPolicy内NavigationService上下文随机为空,如何重新初始化?
解决全局Context随机为null的问题
你的问题核心在于navigatorKey.currentContext仅在Navigator组件处于活跃挂载状态时才有效,页面初始化、路由跳转中或组件被销毁时,它会随机变为null。以下是几种可行的解决思路:
方案一:使用全局Provider容器,摆脱对BuildContext的依赖
在App初始化时创建全局Provider容器,直接从容器中获取服务实例,无需依赖Context:
// 全局Provider容器 final globalProviderContainer = ProviderContainer(); // 在App入口配置 Widget build(BuildContext context) { return UncontrolledProviderScope( container: globalProviderContainer, child: MaterialApp( navigatorKey: NavigationService.navigatorKey, // 其他App配置 ), ); } // 修改RetryPolicy代码 class ExpiredTokenRetryPolicy extends RetryPolicy { @override int get maxRetryAttempts => 1; @override bool shouldAttemptRetryOnException(Exception reason) { return false; } @override Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async { if (response.statusCode == 401) { // 直接从全局容器读取服务 await globalProviderContainer.read(userProfileServiceProvider).initLogin(); return true; } return false; } }
方案二:等待Context可用后再执行操作
给NavigationService添加等待Context的方法,确保获取到有效Context后再调用服务:
class NavigationService { static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); // 新增:等待Context变为可用状态 static Future<BuildContext> waitForValidContext() async { if (navigatorKey.currentContext != null) { return navigatorKey.currentContext!; } // 循环等待,直到Context可用 await Future.doWhile(() { return Future.delayed(const Duration(milliseconds: 50), () { return navigatorKey.currentContext == null; }); }); return navigatorKey.currentContext!; } } // 在RetryPolicy中使用 class ExpiredTokenRetryPolicy extends RetryPolicy { @override int get maxRetryAttempts => 1; @override bool shouldAttemptRetryOnException(Exception reason) { return false; } @override Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async { if (response.statusCode == 401) { final validContext = await NavigationService.waitForValidContext(); await Provider.of<UserProfileService>(validContext, listen: false).initLogin(); return true; } return false; } }
方案三:重构认证逻辑,完全脱离Context
把initLogin方法改造成不依赖Flutter Context的独立函数,直接在网络层调用:
// 独立的认证工具类 class AuthUtil { static Future<void> initLogin() async { // 这里实现登录逻辑:比如调用登录API、更新本地Token等 // 全程不需要Context } } // 修改RetryPolicy代码 class ExpiredTokenRetryPolicy extends RetryPolicy { @override int get maxRetryAttempts => 1; @override bool shouldAttemptRetryOnException(Exception reason) { return false; } @override Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async { if (response.statusCode == 401) { await AuthUtil.initLogin(); return true; } return false; } }
建议
优先选择方案一或方案三,因为网络层逻辑(如RetryPolicy)属于非UI层,应尽量避免依赖BuildContext,从根源上消除Context为null的风险。
内容的提问来源于stack exchange,提问作者Bacon
相关产品推荐
相关产品推荐

