如何在单例模式中使用await getApplicationDocumentsDirectory()初始化Dio的Cookie管理
问题原因
你的代码核心问题是:HttpUtil._internal() 构造函数是同步执行的,而 getApplicationDocumentsDirectory() 是异步方法,你调用 getAppDocDir() 之后还没等异步方法返回结果,构造函数就已经执行完成,此时 appDocDir 还是空值,用 ! 强制解包直接会抛出空异常。
最优解决方案
把单例的初始化改为异步触发,在应用启动阶段提前完成初始化操作,修改后的代码如下:
import 'package:cookie_jar/cookie_jar.dart'; import 'package:dio/dio.dart'; import 'package:dio_cookie_manager/dio_cookie_manager.dart'; import 'package:flutter/widgets.dart'; import 'package:path_provider/path_provider.dart'; import 'package:flutter_chat/config/global_config.dart'; class HttpUtil { static HttpUtil? _instance; static Dio? dio; // 私有化构造函数,禁止外部直接实例化 HttpUtil._internal(); // 对外暴露异步获取实例的方法 static Future<HttpUtil> getInstance() async { if (_instance == null) { _instance = HttpUtil._internal(); // 等待目录获取完成后再初始化Dio和Cookie管理器 final appDocDir = await getApplicationDocumentsDirectory(); final cookiePath = "${appDocDir.path}/.cookies/"; dio = Dio(BaseOptions(baseUrl: GlobalConfig.baseUrl)); // 可以在这里配置全局Dio参数 final cookieJar = PersistCookieJar(ignoreExpires: true, storage: FileStorage(cookiePath)); dio?.interceptors.add(CookieManager(cookieJar)); } return _instance!; } // 封装通用GET请求示例 Future<Response> get(String path, {Map<String, dynamic>? queryParams}) async { return await dio!.get(path, queryParameters: queryParams); } // 封装通用POST请求示例 Future<Response> post(String path, {dynamic data}) async { return await dio!.post(path, data: data); } }
使用方法
在应用入口main.dart中提前完成初始化,确保所有网络请求发起前HttpUtil已经准备完成:
void main() async { // 必须先初始化Flutter绑定,否则path_provider调用会报错 WidgetsFlutterBinding.ensureInitialized(); // 等待HttpUtil初始化完成 await HttpUtil.getInstance(); runApp(const MyApp()); }
后续需要发请求时直接调用即可,无需再次等待初始化:
// 发起GET请求示例 final response = await HttpUtil.getInstance().then((util) => util.get("/api/list")); // 或者更简单的写法,因为已经提前初始化完成,直接用同步写法获取已实例化的dio也可以 final response = await HttpUtil.dio?.get("/api/list");
注意事项
- 不要在同步构造函数中依赖异步方法返回的变量,更不要用
!强制解包还未完成赋值的可空变量,极易引发空安全异常 - 所有涉及原生平台调用的插件(比如path_provider),都必须在
WidgetsFlutterBinding.ensureInitialized()执行完成后调用,否则会抛出平台层调用异常
内容的提问来源于stack exchange,提问作者javaMan
相关产品推荐
相关产品推荐

