You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在单例模式中使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 10:27:04