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

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,
                ],
              );
            },
          ),
        ],
      ),
    );
  }
}

核心改动说明

  1. 移除静态成员:将原静态变量改为实例成员,确保每个页面的下载进度独立,避免全局状态冲突。
  2. ValueNotifier传递状态:progressNotifier会在进度变化时主动通知所有监听它的组件,替代setState的手动刷新逻辑。
  3. ValueListenableBuilder自动更新UI:该组件仅会在ValueNotifier值变化时重建内部UI,避免不必要的页面重绘,性能更优。
  4. 完善状态逻辑:新增下载完成、失败的状态处理,让UI展示更完整。

内容的提问来源于stack exchange,提问作者wolfsoft Developer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 00:18:00