1
This commit is contained in:
@@ -40,7 +40,12 @@ class _CameraScreenState extends State<CameraScreen> {
|
||||
|
||||
/// 当前 worker 已加载的模型 id 集合(激活集变化对比用)
|
||||
Set<int> _loadedModelIds = const {};
|
||||
bool _reloadingWorker = false;
|
||||
|
||||
/// 进行中的 worker 重建(并发调用共享,避免重复建/漏建)
|
||||
Future<void>? _reloadInFlight;
|
||||
|
||||
/// ModelManager revision 快照:模型文件更新(自动更新下载新版)也需重建 worker
|
||||
int _lastRevision = -1;
|
||||
|
||||
void _openSettings() {
|
||||
final vm = _viewModel;
|
||||
@@ -90,8 +95,7 @@ class _CameraScreenState extends State<CameraScreen> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'阈值越低识别越灵敏(低分框越多,误报也可能增加);'
|
||||
'不同模型的置信度分布不同,识别不到目标时可适当调低阈值。',
|
||||
'阈值越低识别越灵敏(低分框越多,误报也可能增加)',
|
||||
style: TextStyle(color: Colors.white54, fontSize: 12),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -138,59 +142,72 @@ class _CameraScreenState extends State<CameraScreen> {
|
||||
setState(() => _permissionGranted = granted);
|
||||
if (!granted) return;
|
||||
|
||||
// 模型热更新:启动拉取目录(只拉不下载),此处兜底等待;未下载模型时仅预览
|
||||
if (!ModelManager.instance.ready) {
|
||||
try {
|
||||
await ModelManager.instance
|
||||
.refresh()
|
||||
.timeout(const Duration(seconds: 15));
|
||||
} catch (_) {}
|
||||
}
|
||||
// 模型热更新:启动拉取目录(只拉不下载),兜底等待;已下载/已激活模型
|
||||
// 有新版本时 autoUpdate 自动重下,变化经 _onModelsChanged 重建 worker
|
||||
try {
|
||||
await ModelManager.instance
|
||||
.refresh()
|
||||
.timeout(const Duration(seconds: 15));
|
||||
} catch (_) {}
|
||||
await _reloadWorker();
|
||||
await _startCamera();
|
||||
}
|
||||
|
||||
/// 用当前激活模型重建推理 worker(激活集变化/启动时调用);
|
||||
/// worker 为 null(无激活模型或加载失败)时仅预览并提示。
|
||||
Future<void> _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;
|
||||
/// 并发调用共享同一进行中的重建:refresh 通知触发的重建与 _init 的等待
|
||||
/// 共用一个 Future,相机等重建完成后再启动(避免绑定旧 analyzer)。
|
||||
Future<void> _reloadWorker() {
|
||||
final inFlight = _reloadInFlight;
|
||||
if (inFlight != null) {
|
||||
// 重建进行中:完成后按最新状态复查,期间的变化不丢失
|
||||
return inFlight.then((_) => _reloadWorker()).catchError((_) {});
|
||||
}
|
||||
_reloadInFlight =
|
||||
_doReloadWorker().whenComplete(() => _reloadInFlight = null);
|
||||
return _reloadInFlight!;
|
||||
}
|
||||
|
||||
Future<void> _doReloadWorker() async {
|
||||
final mgr = ModelManager.instance;
|
||||
final models = mgr.models;
|
||||
final ids = models.map((m) => m.datasetId).toSet();
|
||||
final revChanged = mgr.revision != _lastRevision;
|
||||
if (_viewModel != null &&
|
||||
!revChanged &&
|
||||
_loadedModelIds.length == ids.length &&
|
||||
_loadedModelIds.containsAll(ids)) {
|
||||
return; // 激活集/模型文件未变(进度/目录刷新通知)直接跳过
|
||||
}
|
||||
_lastRevision = mgr.revision;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void _onModelsChanged() {
|
||||
final ids = ModelManager.instance.models.map((m) => m.datasetId).toSet();
|
||||
if (_loadedModelIds.length == ids.length &&
|
||||
final mgr = ModelManager.instance;
|
||||
final ids = mgr.models.map((m) => m.datasetId).toSet();
|
||||
final revChanged = mgr.revision != _lastRevision;
|
||||
if (!revChanged &&
|
||||
_loadedModelIds.length == ids.length &&
|
||||
_loadedModelIds.containsAll(ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user