Flutter BLoCProvider新值不更新:API Key无法实时生效求助
问题:API Key更新后无法实时生效,需重启App才生效
作为Flutter BLoC新手,跟着视频教程开发股票应用并实现自定义功能时,遇到以下问题:用户更新API Key后,新Key无法实时生效,必须重启App才会使用新Key,首次输入的Key会一直被沿用。
问题原因
AppStateCubit和对应的Api实例仅在SearchWidget初始构建时,通过BlocProvider.create创建一次- 当更新
_apiKey并调用setState触发重建时,BlocProvider不会自动重新创建AppStateCubit,导致旧的Api实例(携带旧API Key)持续被使用
解决方案
方案一:通过Key触发BlocProvider重建(简单直接)
在SearchWidget的build方法中,给BlocProvider添加一个基于_apiKey的ValueKey。当_apiKey变化时,Key会改变,强制BlocProvider销毁旧的AppStateCubit并创建新实例,从而使用新的API Key。
修改SearchWidgetState的build方法:
@override Widget build(BuildContext context) { return BlocProvider( key: ValueKey(_apiKey), // 添加此Key,以_apiKey变化触发重建 create: (_) => AppStateCubit(Api(Api.buildDefaultHttpClient(_apiKey))), child: ValueListenableBuilder( valueListenable: _loginWidgetNotifier, builder: (context, loginWidgetValue, child) { // 原代码保持不变 }, ), ); }
方案二:动态更新API Key(无需重建Cubit,更高效)
如果不想重建AppStateCubit,可以修改Api和AppStateCubit,支持动态更新API Key:
- 修改
Api类,添加API Key更新方法,并在请求时使用当前Key:
class Api { final Dio _dio; String _apiKey; Api(this._dio, String apiKey) : _apiKey = apiKey; static Dio buildDefaultHttpClient() { final dio = Dio(); dio.options.baseUrl = "https://finnhub.io/api"; // 移除原拦截器中的token设置,改为在请求时动态添加 return dio; } // 更新API Key的方法 void updateApiKey(String newApiKey) { _apiKey = newApiKey; } Future<List<Candle>> getCandles(GetCandlesRequest request) async { try { final response = await _dio.get<Map<String, dynamic>>( "/v1/stock/candle", queryParameters: { ...request.toJson(), "token": _apiKey, // 动态使用当前API Key }, ); final candlesPayload = CandlesPayload.fromJson(response.data!); return candlesPayload.toCandles(); } catch (e, s) { debugPrint("$e\n$s"); throw ApiException("An unknown error occurred"); } } }
- 修改
AppStateCubit,添加更新API Key的方法:
class AppStateCubit extends Cubit<AppState> { final Api _api; AppStateCubit(this._api) : super(AppState.initial()); // 添加更新API Key的方法 void updateApiKey(String newApiKey) { _api.updateApiKey(newApiKey); } // 原loadCandles方法保持不变 }
- 在
SearchWidgetState的enterApiKey方法中,更新API Key后通知Cubit:
onPressed: () { if (apiKey.isNotEmpty) { setState(() { _apiKey = apiKey; _loginWidget = false; error = false; apiKey = ''; }); // 获取Cubit实例并更新API Key context.read<AppStateCubit>().updateApiKey(_apiKey); saveApiKey(); saveLoginState(); Navigator.of(context).pop(); } else { setState(() { error = true; }); } }
同时,修改SearchWidgetState中创建Api的代码:
create: (_) => AppStateCubit(Api(Api.buildDefaultHttpClient(), _apiKey)),
验证
完成修改后,更新API Key并关闭弹窗,后续的API请求就会使用新的Key,无需重启App。
内容的提问来源于stack exchange,提问作者deandrehaijiel
相关产品推荐
相关产品推荐

