Flutter中无需setState更新下载进度视图的实现方案
问题解决:无需
setState实现Flutter下载进度实时更新 你当前的问题核心在于静态变量statusValue无法触发UI的实时更新,哪怕调用setState也仅会刷新一次,无法响应下载过程中的进度变化。要实现无setState的实时更新,可使用Flutter原生轻量状态管理方案:ValueNotifier + ValueListenableBuilder。
第一步:重构DioFileDownloader类
将原有的静态成员改为实例成员,利用ValueNotifier传递进度变化信号:
import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:nb_utils/nb_utils.dart'; import 'package:world_virtual_coin/widget/colors.dart'; import 'package:world_virtual_coin/widget/custom_text.dart'; class DioFileDownloader { // 用于通知进度变化的ValueNotifier,初始值0.0 final ValueNotifier<double> progressNotifier = ValueNotifier(0.0); final Dio dioObject = Dio(); Future download(String url, String savePath) async { progressNotifier.value = 0.0; // 下载开始前重置进度 try { Response response = await dioObject.get( url, onReceiveProgress: _updateDownloadProgress, options: Options( responseType: ResponseType.bytes, followRedirects: false, validateStatus: (status) => status! < 500, ), ); File file = File(savePath); var raf = file.openSync(mode: FileMode.write); raf.writeFromSync(response.data); await raf.close(); progressNotifier.value = 100.0; // 下载完成后标记为100% } catch (e) { print(e); progressNotifier.value = -1; // 标记下载失败状态 } } void _updateDownloadProgress(int received, int total) { if (total != -1) { final progress = (received / total) * 100; progressNotifier.value = progress; // 实时更新进度值,通知监听者 print("DownloadStatus : ${progress.toStringAsFixed(0)}%"); } } }
第二步:页面中调用并展示实时进度
在页面中创建下载器实例,通过ValueListenableBuilder监听进度变化,自动更新UI:
class YourPage extends StatefulWidget { const YourPage({super.key}); @override State<YourPage> createState() => _YourPageState(); } class _YourPageState extends State<YourPage> { // 创建下载器实例 final DioFileDownloader _downloader = DioFileDownloader(); @override Widget build(BuildContext context) { return Scaffold( // ... 其他页面内容 body: Column( children: [ CustomButton( onPressed: () async { var tempDir = await getTemporaryDirectory(); // 修正原代码中的单引号错误 String fullPath = "${tempDir.path}/dummy.pdf"; print('full path $fullPath'); File file = File(fullPath); if (await file.exists() && Platform.isAndroid) { OpenFile.open(file.path); } else { await _downloader.download(imgUrl, fullPath); } }, label: 'Save Pdf', ), // 监听进度变化,自动更新UI ValueListenableBuilder<double>( valueListenable: _downloader.progressNotifier, builder: (context, progress, child) { // 根据进度值生成对应文本 String statusText = progress == -1 ? "下载失败" : progress == 100.0 ? "下载完成" : "${progress.toStringAsFixed(0)}%"; return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ CustomText( statusText, fontSize: 15, isCentered: true, textColor: const Color(0XFF161618), ), // 仅在下载中显示"Downloading"文本 if (progress > 0 && progress < 100) CustomText( " Downloading", fontSize: 15, isCentered: true, textColor: colorPrimary, ), 30.height, ], ); }, ), ], ), ); } }
核心改动说明
- 移除静态成员:将原静态变量改为实例成员,确保每个页面的下载进度独立,避免全局状态冲突。
ValueNotifier传递状态:progressNotifier会在进度变化时主动通知所有监听它的组件,替代setState的手动刷新逻辑。ValueListenableBuilder自动更新UI:该组件仅会在ValueNotifier值变化时重建内部UI,避免不必要的页面重绘,性能更优。- 完善状态逻辑:新增下载完成、失败的状态处理,让UI展示更完整。
内容的提问来源于stack exchange,提问作者wolfsoft Developer
相关产品推荐
相关产品推荐

