优化部分功能逻辑:元数据信息漂移

优化部分体验问题,包含动画、界面层级等
This commit is contained in:
2026-08-26 21:13:09 +08:00
parent 94d37fe263
commit 8f3f827429
3 changed files with 251 additions and 198 deletions
+59 -27
View File
@@ -3,6 +3,7 @@ import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:media_kit/media_kit.dart';
import 'package:path_provider/path_provider.dart';
import 'playback_service.dart';
import '../metadata/metadata_service.dart';
@@ -60,6 +61,9 @@ class AudioService extends ChangeNotifier {
bool _isUserSeeking = false;
// ⭐ 播放代数:每次切歌递增,用于校验异步任务是否过期
int _playbackGeneration = 0;
// ---- Getter ----
Song? get currentSong => _currentSong;
bool get isPlaying => _isPlaying;
@@ -144,6 +148,9 @@ class AudioService extends ChangeNotifier {
return;
}
_playbackGeneration++;
final generation = _playbackGeneration;
final song = _queue[_currentIndex];
_currentSong = song;
@@ -158,7 +165,11 @@ class AudioService extends ChangeNotifier {
_syncPlayerStateDelayed();
_loadMetadataForCurrentSong();
// ⭐ 立即推送基本信息(无 artwork)
_onSongChanged?.call(song);
// ⭐ 异步加载完整 metadata(含 artwork
_loadMetadataForCurrentSong(generation);
}
String _generateSongKey(String url, int fileSize, int modifiedTime) {
@@ -166,10 +177,21 @@ class AudioService extends ChangeNotifier {
return raw.hashCode.toString();
}
Future<void> _loadMetadataForCurrentSong() async {
// ⭐ 核心:带 generation 校验的 metadata 加载
// lib/services/audio_service.dart
Future<void> _loadMetadataForCurrentSong(int generation) async {
if (_currentIndex < 0 || _currentIndex >= _queue.length) return;
final song = _queue[_currentIndex];
if (song.url == null || song.url!.isEmpty) return;
final currentIndex = _currentIndex;
final song = _queue[currentIndex];
final songId = song.id;
if (song.url == null || song.url!.isEmpty) {
// 没有 URL,直接推送 fallback
_onSongChanged?.call(song);
return;
}
try {
final metadata = await MetadataService().getMetadata(
@@ -178,23 +200,41 @@ class AudioService extends ChangeNotifier {
fileId: song.id,
);
if (metadata.isNotEmpty) {
final updatedSong = Song(
id: song.id,
title: metadata.title.isNotEmpty ? metadata.title : song.title,
artist: metadata.artist.isNotEmpty ? metadata.artist : song.artist,
url: song.url,
artwork: metadata.artwork, // ✅ 已有
);
_queue[_currentIndex] = updatedSong;
_currentSong = updatedSong;
notifyListeners();
// ⭐ 传递完整的 updatedSong(包含 artwork
_onSongChanged?.call(updatedSong);
// generation 校验
if (_playbackGeneration != generation) {
debugPrint('⚠️ [AudioService] metadata stale (generation), ignoring');
return;
}
if (_currentIndex != currentIndex) {
debugPrint(
'⚠️ [AudioService] metadata stale (index changed), ignoring');
return;
}
if (currentIndex >= _queue.length || _queue[currentIndex].id != songId) {
debugPrint('⚠️ [AudioService] metadata stale (song changed), ignoring');
return;
}
// 更新 Song
final updatedSong = Song(
id: song.id,
title: metadata.title.isNotEmpty ? metadata.title : song.title,
artist: metadata.artist.isNotEmpty ? metadata.artist : song.artist,
url: song.url,
artwork: metadata.artwork,
);
_queue[_currentIndex] = updatedSong;
_currentSong = updatedSong;
notifyListeners();
// ⭐ 一次性推送完整数据(含 artwork)
_onSongChanged?.call(updatedSong);
debugPrint(
'✅ [AudioService] metadata updated: ${updatedSong.title} - ${updatedSong.artist} (generation $generation)');
} catch (e) {
debugPrint('⚠️ [AudioService] metadata load failed: $e');
debugPrint('⚠️ [AudioService] metadata load failed: $e, using fallback');
// 异常时推送 fallback(无 artwork
_onSongChanged?.call(song);
}
}
@@ -207,10 +247,8 @@ class AudioService extends ChangeNotifier {
debugPrint('🗑️ [AudioService] clearing cache for: ${song.title}');
// 1. 获取当前索引
final currentIndex = _currentIndex;
// 2. 尝试获取文件信息生成 song_key
String songKey;
try {
final provider = MetadataService().getProviderForUrl(url);
@@ -226,17 +264,14 @@ class AudioService extends ChangeNotifier {
songKey = url.hashCode.toString();
}
// 3. 清除 SQLite 记录
final db = SongDatabase();
await db.deleteSong(songKey);
await db.deleteCache(songKey);
debugPrint('🗑️ [AudioService] SQLite records deleted: $songKey');
// 4. 删除封面图
await ArtworkHelper.deleteArtwork(songKey);
debugPrint('🗑️ [AudioService] artwork deleted');
// 5. 删除 metadata 临时缓存文件
try {
final cacheDir = await getTemporaryDirectory();
final cachePath = '${cacheDir.path}/metadata_${url.hashCode}.tmp';
@@ -249,14 +284,11 @@ class AudioService extends ChangeNotifier {
// 忽略
}
// 6. 清除内存缓存
await MetadataService().clearCache(song.id);
debugPrint('🗑️ [AudioService] memory cache cleared');
// 7. 停止并重新播放
if (currentIndex >= 0 && currentIndex < _queue.length) {
stopPlay();
// 确保重新播放同一首歌
_playCurrent();
debugPrint('🔄 [AudioService] song reloaded');
}