From 0bd1af3b42cc5b8456ed947bc03448bafed14eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Tue, 1 Sep 2026 09:06:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(app):=20=E6=BF=80=E6=B4=BB=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E5=8F=98=E5=8C=96=E6=97=B6=E9=87=8D=E5=BB=BA=E6=8E=A8?= =?UTF-8?q?=E7=90=86=20worker=EF=BC=88=E6=97=A0=E6=A8=A1=E5=9E=8B=E4=BB=85?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E5=B9=B6=E6=8F=90=E7=A4=BA=E9=80=89=E6=8B=A9?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ModelManager 激活集变化(下载完成自动激活/取消激活/目录刷新)时经 _onModelsChanged 触发 _reloadWorker:激活集未变直接跳过,变了则重建 worker+analyzer 并重启帧流;无激活模型时仅预览,横幅区分 「未使用模型:点右上角设置…」与「识别模型加载失败…」。 --- flutter_app/lib/camera/camera_screen.dart | 76 +++++++++++++++++------ 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/flutter_app/lib/camera/camera_screen.dart b/flutter_app/lib/camera/camera_screen.dart index ff31545..65ff49a 100644 --- a/flutter_app/lib/camera/camera_screen.dart +++ b/flutter_app/lib/camera/camera_screen.dart @@ -38,6 +38,10 @@ class _CameraScreenState extends State { Map _nativeStats = const {}; Timer? _statsTimer; + /// 当前 worker 已加载的模型 id 集合(激活集变化对比用) + Set _loadedModelIds = const {}; + bool _reloadingWorker = false; + void _openSettings() { final vm = _viewModel; if (vm == null) return; @@ -116,6 +120,8 @@ class _CameraScreenState extends State { WakelockPlus.enable(); // 每秒轮询原生侧帧状态:无帧时诊断行也能实时刷新(camErr/计数) _statsTimer = Timer.periodic(const Duration(seconds: 1), (_) => _pollStats()); + // 模型清单激活集变化(下载完成自动激活/取消激活)时重建推理 worker + ModelManager.instance.addListener(_onModelsChanged); } Future _pollStats() async { @@ -132,8 +138,7 @@ class _CameraScreenState extends State { setState(() => _permissionGranted = granted); if (!granted) return; - // 模型热更新:优先使用已下载的数据集模型(启动时后台拉取;此处兜底等待, - // 下载慢/失败不阻塞相机启动——无下载模型时仅预览) + // 模型热更新:启动拉取目录(只拉不下载),此处兜底等待;未下载模型时仅预览 if (!ModelManager.instance.ready) { try { await ModelManager.instance @@ -141,23 +146,55 @@ class _CameraScreenState extends State { .timeout(const Duration(seconds: 15)); } catch (_) {} } - // 模型加载/推理在后台 isolate,不阻塞 UI;worker 为 null 时仅预览并提示 - final worker = await DetectorWorker.create( - models: ModelManager.instance.models); - final viewModel = CameraViewModel(reminder: Reminder()); - viewModel.setModelReady(worker != null); - final analyzer = FrameAnalyzer(worker: worker, viewModel: viewModel); - if (!mounted) { - analyzer.dispose(); - viewModel.dispose(); + await _reloadWorker(); + await _startCamera(); + } + + /// 用当前激活模型重建推理 worker(激活集变化/启动时调用); + /// worker 为 null(无激活模型或加载失败)时仅预览并提示。 + Future _reloadWorker() async { + if (_reloadingWorker) return; + _reloadingWorker = true; + try { + final models = ModelManager.instance.models; + final ids = models.map((m) => m.datasetId).toSet(); + if (_viewModel != null && + _loadedModelIds.length == ids.length && + _loadedModelIds.containsAll(ids)) { + return; // 激活集未变(进度/目录刷新通知)直接跳过 + } + final worker = await DetectorWorker.create(models: models); + _loadedModelIds = ids; + final vm = _viewModel ?? CameraViewModel(reminder: Reminder()); + vm.setModelReady(worker != null); + final analyzer = FrameAnalyzer(worker: worker, viewModel: vm); + final old = _analyzer; + if (!mounted) { + analyzer.dispose(); + if (vm != _viewModel) vm.dispose(); + return; + } + setState(() { + _viewModel = vm; + _analyzer = analyzer; + }); + old?.worker?.dispose(); + // 相机已启动:重启帧流绑定新 analyzer(start 内部先 stop 再订阅) + if (mounted && _cameraController != null) { + await _cameraController!.start(analyzer); + } + } finally { + _reloadingWorker = false; + } + } + + void _onModelsChanged() { + final ids = ModelManager.instance.models.map((m) => m.datasetId).toSet(); + if (_loadedModelIds.length == ids.length && + _loadedModelIds.containsAll(ids)) { return; } - setState(() { - _viewModel = viewModel; - _analyzer = analyzer; - }); - - await _startCamera(); + _reloadWorker(); } Future _startCamera() async { @@ -193,6 +230,7 @@ class _CameraScreenState extends State { @override void dispose() { + ModelManager.instance.removeListener(_onModelsChanged); _statsTimer?.cancel(); WakelockPlus.disable(); _cameraController?.stop(); @@ -333,7 +371,9 @@ class _CameraScreenState extends State { borderRadius: BorderRadius.circular(8), ), child: Text( - '识别模型加载失败:${DetectorWorker.lastLoadError ?? '未知原因'}\n最后步骤:${DetectorWorker.lastLog ?? '-'}', + ModelManager.instance.models.isEmpty + ? '未使用模型:点右上角设置,在「模型清单」中选择要使用的模型' + : '识别模型加载失败:${DetectorWorker.lastLoadError ?? '未知原因'}\n最后步骤:${DetectorWorker.lastLog ?? '-'}', textAlign: TextAlign.center, style: const TextStyle(color: Colors.orange, fontSize: 14), ),