static + final = 唯一 + 不可修改
问题static final DioRequest _instance DioRequest._init();如果只用final行不行为啥两个关键字连用才能保证单一实例且只会执行一个初始化解答这是一个非常棒的问题触及了 Dart 语言底层设计的核心。简单来说static 决定了“在那儿”final 决定了“不可变”两者结合才构成了“唯一且安全的单例”。我们可以拆开来看1. 为什么必须有 static空间唯一性如果去掉 static只写 final DioRequest _instance …•变成了“成员变量”它就属于每一个具体的对象而不是属于类。•逻辑死循环每次你创建一个 DioRequest它内部又会去初始化一个 _instance这个 _instance 又是一个新的 DioRequest…… 结果就是导致内存溢出Stack Overflow。•结论static 确保了无论你的 App 运行多久在内存中 _instance 这个变量名只占一个坑位它是类级别的全局共享。2. 为什么必须有 final时间唯一性/安全性如果去掉 final只写 static DioRequest _instance …• 可以被修改虽然它是唯一的但它是“可写的”。这意味着代码里任何地方都可以通过 DioRequest._instance DioRequest._init(); 强行覆盖掉它。• 单例失效一旦被覆盖旧的实例和它里面已经配置好的 _dio 就会被销毁或失去引用单例的“持久性”就没了。•结论final 保证了 “这个坑位一旦填上了谁也别想换掉它”3. 为什么“只会执行一次初始化”这是 Dart 语言的一个非常重要的特性静态变量是“懒加载Lazy Initialization”的。当你写staticfinalDioRequest_instanceDioRequest._init();Dart 引擎并不会在程序启动时立刻运行 _init()。它会一直等等到你第一次在代码中访问 DioRequest() 时1.引擎发现 _instance 还没初始化。2.执行 DioRequest._init()。3.把返回的结果塞进 _instance 这个坑位。4.因为有 final标记这个坑位为“已锁死”。5.以后所有的访问引擎都直接从这个坑位拿值不再运行 _init()。总结如果只用 final 行不行•在类内部不行。会导致上面说的死循环或变成普通成员变量。•在类外部文件顶层可以。其实代码最后一行写的就是这种方式finaldioRequestDioRequest();// 这也是一种单例因为它在全局作用域但是 即使你在外面定义了 final dioRequest如果类内部不写 static final _instance 加 factory 构造函数别人依然可以通过 DioRequest() 创建新的实例。最标准的做法你现在的写法 通过 static final _instance 配合私有构造函数从物理上锁死了外部创建第二个对象的可能性。这才是真正的单例模式。最开始的一版是这样写的importpackage:dio/dio.dart;importpackage:flutter_learn/app/stores/TokenManager.dart;import../constants/index.dart;classDioRequest{// 1.内部私有化的 Dio 实例这才是真正发送额请求的对象staticfinalDio_dioDio();// 构造函数DioRequest(){_dio.options..baseUrlGlobalConstants.BASE_URL..sendTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT)..connectTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT)..receiveTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT);//拦截器_addInterceptors();}//....此处为了方便比较省略详细代码// 单例对象finaldioRequestDioRequest();会有问题在 Dart 中你目前的写法在文件顶层定义 final dioRequest DioRequest();确实可以让外部通过这个变量使用同一个实例起到“全局单例”的作用。但是从严格的单例模式和代码健壮性角度来看目前的写法存在两个问题并没有阻止外部创建新实例虽然你定义了 dioRequest但外部仍然可以调用 DioRequest() 来创建一个全新的对象。潜在的 Bug重复添加拦截器由于你的 _dio 是 static静态的staticfinalDio_dioDio();这意味着无论你创建多少个 DioRequest 对象它们都共享同一个 _dio。 而在你的构造函数里DioRequest(){// ... 配置 options_addInterceptors();// 每次创建实例都会执行}如果有人不小心多次调用了 DioRequest()_addInterceptors() 就会被多次执行导致同一个 _dio 实例上挂载了多个重复的拦截器。这会导致每次请求时拦截器里的代码比如打印日志、添加 Token运行多次。推荐的改进写法标准单例模式为了确保真正的单例并避免重复初始化建议这样修改importpackage:dio/dio.dart;importpackage:flutter_learn/app/stores/TokenManager.dart;import../constants/index.dart;classDioRequest{// 1.内部私有化的 Dio 实例这才是真正发送额请求的对象staticfinalDio_dioDio();// 2.静态私有变量保存 DioRequest 的唯一实例staticfinalDioRequest_instanceDioRequest._init();// 3.工厂构造函数当外部调用 DioResquest()时返回那一个唯一的 _instancefactoryDioRequest()_instance;// 构造函数// DioRequest() {// 4.私有化构造函数用于初始化配置DioRequest._init(){_dio.options..baseUrlGlobalConstants.BASE_URL..sendTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT)..connectTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT)..receiveTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT);//拦截器_addInterceptors();}//....此处为了方便比较省略详细代码// 单例对象finaldioRequestDioRequest();1.使用._init()私有化构造函数。2.确保_addInterreceptors()只在整个App生命周期内执行一次。ps:附上最后完整类// 基于Dio的网络请求工具类importpackage:dio/dio.dart;importpackage:flutter_learn/app/stores/TokenManager.dart;import../constants/index.dart;classDioRequest{// 1.内部私有化的 Dio 实例这才是真正发送额请求的对象staticfinalDio_dioDio();// 2.静态私有变量保存 DioRequest 的唯一实例staticfinalDioRequest_instanceDioRequest._init();// 3.工厂构造函数当外部调用 DioResquest()时返回那一个唯一的 _instancefactoryDioRequest()_instance;// 构造函数// DioRequest() {// 4.私有化构造函数用于初始化配置DioRequest._init(){_dio.options..baseUrlGlobalConstants.BASE_URL..sendTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT)..connectTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT)..receiveTimeoutDuration(milliseconds:GlobalConstants.TIME_OUT);//拦截器_addInterceptors();}// 添加拦截器void_addInterceptors(){_dio.interceptors.add(InterceptorsWrapper(onRequest:(request,handler){// 注入token request headers Authorization Bearer $tokenif(tokenManager.getToken().isNotEmpty){request.headers[Authorization]Bearer${tokenManager.getToken()};}print( 打印网络请求URL ${request.uri.toString()});// 在发送请求之前做一些事情handler.next(request);// 继续发送请求},onResponse:(response,handler){// 在收到响应之前做一些事情if(response.statusCode!nullresponse.statusCode!200response.statusCode!300){handler.next(response);// 继续处理响应}else{handler.reject(DioException(requestOptions:response.requestOptions),);// 继续处理响应}},onError:(DioExceptione,handler){// 在发生错误之前做一些事情// handler.reject(e); // 继续处理错误handler.reject(DioException(requestOptions:e.requestOptions,message:e.response?.data[msg]?? ,),);},),);}// 写了两层Future包裹就会报错// FutureFuturedynamic get(String url,{MapString,dynamic? params}) async{Futuredynamicget(Stringurl,{MapString,dynamic?params}){return_handlerResponse(_dio.get(url,queryParameters:params));}Futuredynamicpost(Stringurl,{MapString,dynamic?data}){return_handlerResponse(_dio.post(url,data:data));}Futuredynamic_handlerResponse(FutureResponsedynamictask)async{try{Responsedynamicresponseawaittask;finaldataresponse.dataasMapString,dynamic;// 业务状态码 是 1 ,不是数字 1if(data[code]GlobalConstants.SUCCESS_CODE){print( 加载数据成功 ${data[result]});returndata[result];}// throw Exception(data[msg] ?? 加载数据异常);throwDioException(requestOptions:response.requestOptions,message:data[msg]??加载数据异常,);}catch(e){// throw Exception(catch 加载数据异常 $e);rethrow;// 不改变原来抛出的异常类型}}}// 单例对象finaldioRequestDioRequest();// dio请求工具发出请求 返回的数据 Responsedynamic.data// 把 Responsedynamic.data 转换为 MapString,dynamic// 把所有的接口的data解放出来// 拿到真正的数据 要判断业务状态码是不是等于1

相关新闻

Vxe-Grid表格编辑进阶:如何优雅处理单元格事件与数据联动

Vxe-Grid表格编辑进阶:如何优雅处理单元格事件与数据联动

Vxe-Grid表格编辑进阶:如何优雅处理单元格事件与数据联动 如果你正在构建一个需要复杂数据交互的前端应用,比如财务系统、库存管理或者供应链管理平台,那么表格组件很可能就是你最核心的战场。在这些场景里,表格不仅仅是展示数据的…

2026/5/17 11:35:06 阅读更多 →
MyClaw 初体验:从零配置到成功调用 SiliconFlow 的完整记录

MyClaw 初体验:从零配置到成功调用 SiliconFlow 的完整记录

MyClaw 初体验:从零配置到成功调用 SiliconFlow 的完整记录 缘起:一款新发布的桌面 AI 助手 今天从朋友新发布的网站 https://deepseekmine.com/myclaw 下载了 MyClaw 桌面版(v1.0.2)。这是一款刚亮相的本地 AI 助手&#xff0c…

2026/7/3 17:13:23 阅读更多 →
408考研操作系统必考:时间片轮转调度算法的实战应用与优化策略

408考研操作系统必考:时间片轮转调度算法的实战应用与优化策略

1. 从一道让很多人栽跟头的408真题说起 如果你正在备战408考研,操作系统这门课里的调度算法绝对是绕不开的重点。而时间片轮转调度算法,更是每年真题里的“常客”。去年,也就是2024年的408真题里,就出了一道关于它的计算题&#x…

2026/5/17 11:35:04 阅读更多 →

最新新闻

大模型API商用成本拆解:Token计价、上下文溢价与企业级隐性费用

大模型API商用成本拆解:Token计价、上下文溢价与企业级隐性费用

1. 这份价格表不是“查价工具”,而是商用决策的导航仪你手头正跑着一个客户定制的智能客服项目,月底要签二期合同;或者刚在内部立项了AI辅助写周报的SaaS功能,技术方案定了,但财务部卡在成本测算环节;又或者…

2026/7/4 10:44:21 阅读更多 →
AI就绪笔记本采购指南:硬件选型与代码大模型落地实战

AI就绪笔记本采购指南:硬件选型与代码大模型落地实战

1. 项目概述:这不是一份普通早报,而是一份面向技术决策者与硬件从业者的“信号解码器”“通讯Plus早报|24年笔记本电脑出货量或超1亿 信通院公布AI代码大模型评估”——这个标题里藏着两股真实涌动的产业暗流。它不是媒体通稿的简单搬运&…

2026/7/4 10:44:21 阅读更多 →
YOLOv8中GAM注意力机制的实现与优化

YOLOv8中GAM注意力机制的实现与优化

1. GAM注意力机制的技术背景与核心价值 在目标检测领域,YOLOv8作为当前最先进的实时检测框架,其性能提升一直备受关注。传统卷积神经网络在处理特征图时存在一个根本性局限:所有空间位置和通道维度都被平等对待,而实际上不同区域和…

2026/7/4 10:40:19 阅读更多 →
基于YOLOv8的红外光伏板缺陷检测系统设计与实现

基于YOLOv8的红外光伏板缺陷检测系统设计与实现

1. 项目概述:基于YOLOv8的红外光伏板缺陷检测系统光伏板作为清洁能源的核心组件,其表面缺陷会直接影响发电效率。传统人工检测方式效率低下且容易漏检,我们团队开发的这套系统采用YOLOv8目标检测算法,实现了对光伏板缺陷的自动化识…

2026/7/4 10:40:19 阅读更多 →
从AI小白到高效协作者:普通人快速上手的实战指南

从AI小白到高效协作者:普通人快速上手的实战指南

1. 项目概述:为什么“ALL IN AI”不再是口号最近和不少朋友聊天,发现一个挺有意思的现象:前两年大家聊起AI,还觉得是硅谷大厂和顶尖实验室的“神仙打架”,离自己很远。但今年,从写周报、做PPT,到…

2026/7/4 10:38:18 阅读更多 →
13DOF传感器与MKV46F128VLH16微控制器的嵌入式导航方案

13DOF传感器与MKV46F128VLH16微控制器的嵌入式导航方案

1. 13DOF传感器与MKV46F128VLH16微控制器的技术背景在嵌入式定位导航领域,13DOF(13自由度)传感器组合与MKV46F128VLH16微控制器的搭配已经成为工业级应用的黄金组合。13DOF通常由三轴加速度计、三轴陀螺仪、三轴磁力计、气压计和温度传感器组…

2026/7/4 10:36:18 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻