From cfa0e2ca40b8b5533a92a7d9ae51b37ea83a2507 Mon Sep 17 00:00:00 2001 From: hailin Date: Fri, 30 Jan 2026 12:24:47 -0800 Subject: [PATCH] =?UTF-8?q?fix(mining-app):=20=E6=9B=B4=E6=96=B0=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E7=82=B9=E5=87=BB"=E7=AB=8B=E5=8D=B3=E6=9B=B4?= =?UTF-8?q?=E6=96=B0"=E6=97=A0=E5=8F=8D=E5=BA=94=20=E2=80=94=20=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=E6=B5=81=E8=AE=A2=E9=98=85=E7=AB=9E=E6=80=81=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题根因: SelfHostedUpdater._listenToProgress() 在 initState 和 _startDownload 中 订阅 UpdateService.downloadProgressStream,但该 getter 返回 _downloadManager?.progressStream —— _downloadManager 在 downloadUpdate() 调用前为 null,?.listen 无操作。downloadUpdate() 创建新 _downloadManager 后,其 progressStream 无人监听,进度事件全部丢失,UI 无任何反馈。 修复: 1. UpdateService 新增持久化广播流 _downloadProgressController, downloadUpdate() 创建新 DownloadManager 后将其进度转发到此流 2. downloadProgressStream getter 改为返回持久化流(非 nullable) 3. SelfHostedUpdater 在 initState 中一次性订阅持久化流, dispose 时取消订阅,_startDownload 不再重复订阅 Co-Authored-By: Claude Opus 4.5 --- .../updater/channels/self_hosted_updater.dart | 17 ++++++++++------- .../lib/core/updater/update_service.dart | 18 +++++++++++++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/frontend/mining-app/lib/core/updater/channels/self_hosted_updater.dart b/frontend/mining-app/lib/core/updater/channels/self_hosted_updater.dart index 74fcf5d7..366dcb2f 100644 --- a/frontend/mining-app/lib/core/updater/channels/self_hosted_updater.dart +++ b/frontend/mining-app/lib/core/updater/channels/self_hosted_updater.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import '../models/version_info.dart'; @@ -48,15 +49,13 @@ class _SelfHostedUpdaterState extends State { DownloadProgress _progress = DownloadProgress.initial(); File? _downloadedFile; bool _isDownloading = false; + StreamSubscription? _progressSubscription; @override void initState() { super.initState(); - _listenToProgress(); - } - - void _listenToProgress() { - UpdateService.instance.downloadProgressStream?.listen((progress) { + // 订阅持久化广播流,无论何时开始下载都能收到进度 + _progressSubscription = UpdateService.instance.downloadProgressStream.listen((progress) { if (mounted) { setState(() { _progress = progress; @@ -65,6 +64,12 @@ class _SelfHostedUpdaterState extends State { }); } + @override + void dispose() { + _progressSubscription?.cancel(); + super.dispose(); + } + Future _startDownload() async { setState(() { _isDownloading = true; @@ -73,8 +78,6 @@ class _SelfHostedUpdaterState extends State { ); }); - _listenToProgress(); - final file = await UpdateService.instance.downloadUpdate(widget.versionInfo); if (mounted) { diff --git a/frontend/mining-app/lib/core/updater/update_service.dart b/frontend/mining-app/lib/core/updater/update_service.dart index 26b0c4c1..91cd80c0 100644 --- a/frontend/mining-app/lib/core/updater/update_service.dart +++ b/frontend/mining-app/lib/core/updater/update_service.dart @@ -51,6 +51,10 @@ class UpdateService { final _updateAvailableController = StreamController.broadcast(); Stream get updateAvailableStream => _updateAvailableController.stream; + /// 持久化的下载进度流(跨 DownloadManager 实例保持订阅有效) + final _downloadProgressController = StreamController.broadcast(); + StreamSubscription? _downloadProgressSubscription; + VersionInfo? _latestVersion; VersionInfo? get latestVersion => _latestVersion; @@ -126,14 +130,20 @@ class UpdateService { /// 下载更新 Future downloadUpdate(VersionInfo versionInfo) async { + // 取消旧的进度转发订阅 + await _downloadProgressSubscription?.cancel(); _downloadManager?.dispose(); _downloadManager = DownloadManager(versionInfo: versionInfo); + // 将新 DownloadManager 的进度转发到持久化广播流 + _downloadProgressSubscription = _downloadManager!.progressStream.listen( + (progress) => _downloadProgressController.add(progress), + ); return await _downloadManager!.startDownload(); } - /// 获取下载进度流 - Stream? get downloadProgressStream => - _downloadManager?.progressStream; + /// 获取下载进度流(持久化广播流,订阅后可跨下载任务接收进度) + Stream get downloadProgressStream => + _downloadProgressController.stream; /// 取消下载 void cancelDownload() { @@ -166,7 +176,9 @@ class UpdateService { } void dispose() { + _downloadProgressSubscription?.cancel(); _downloadManager?.dispose(); + _downloadProgressController.close(); _updateAvailableController.close(); } }