Flutter中使用just_audio加载大音频播放列表优化方案咨询
优化Flutter音乐应用播放列表加载速度问题
我使用just_audio和just_audio_background开发了一款Flutter音乐应用,音乐功能及控件运行正常,但加载包含至少20首长时长歌曲的播放列表时耗时过长。当前实现方式如下:
//Generating list list.add(AudioSource.uri( Uri.parse(musicDetails!.trackFileUrl!), tag: MediaItem( id: currentSongIndex.toString(), album: musicDetails!.description ?? "", title: musicDetails!.title ?? "", artUri: Uri.parse(musicDetails!.coverImage ?? ""), ), ) ); //Adding entire list to playlist final playlist = ConcatenatingAudioSource(children: list); await player.setLoopMode(LoopMode.all); await player.setAudioSource(playlist,initialIndex: currentSongIndex.value);
我希望修改当前向播放器添加播放列表的实现方式,请问该如何实现以缩短加载时间?
优化方案
1. 动态预加载,避免一次性创建所有音频源
ConcatenatingAudioSource支持动态增删子项,不需要一次性初始化全部歌曲的AudioSource。可以先创建空的拼接源,只预加载当前播放歌曲及前后少量歌曲,剩余歌曲在用户切换曲目或滑动列表时再动态添加,同时移除超出预加载范围的旧源节省资源。
示例代码:
// 初始化空的拼接播放列表 final playlist = ConcatenatingAudioSource(children: []); await player.setAudioSource(playlist, initialIndex: 0); await player.setLoopMode(LoopMode.all); // 定义预加载范围:当前索引前后各3首 void preloadNearbySongs(int currentIndex) { final totalSongs = allMusicDetails.length; final start = max(0, currentIndex - 3); final end = min(totalSongs - 1, currentIndex + 3); // 添加需要预加载的歌曲 for (int i = start; i <= end; i++) { bool exists = playlist.children.any((source) => (source.tag as MediaItem).id == i.toString()); if (!exists) { final audioSource = AudioSource.uri( Uri.parse(allMusicDetails[i].trackFileUrl!), tag: MediaItem( id: i.toString(), album: allMusicDetails[i].description ?? "", title: allMusicDetails[i].title ?? "", artUri: Uri.parse(allMusicDetails[i].coverImage ?? ""), ), ); playlist.insert(i, audioSource); } } // 清理超出预加载范围的旧音频源 final cleanStart = max(0, currentIndex - 6); final cleanEnd = min(totalSongs - 1, currentIndex + 6); // 移除前面的旧源 for (int i = 0; i < cleanStart; i++) { if (i < playlist.children.length) playlist.removeAt(i); } // 移除后面的旧源 for (int i = playlist.children.length - 1; i > cleanEnd; i--) { playlist.removeAt(i); } } // 监听播放器当前索引变化,触发预加载 player.currentIndexStream.listen((index) { if (index != null) preloadNearbySongs(index); }); // 首次加载当前选中的歌曲及附近曲目 preloadNearbySongs(currentSongIndex.value);
2. 自定义懒加载音频源
通过继承AudioSource实现懒加载逻辑,只有当播放器需要播放某首歌时,才去真正创建解析AudioSource.uri,避免一次性解析所有歌曲的URI和元数据。
示例代码:
class LazyAudioSource extends AudioSource { final MusicDetails musicDetails; final int index; LazyAudioSource(this.musicDetails, this.index); @override Future<AudioSource> resolve() async { // 仅在需要播放时才创建实际的音频源 return AudioSource.uri( Uri.parse(musicDetails.trackFileUrl!), tag: MediaItem( id: index.toString(), album: musicDetails.description ?? "", title: musicDetails.title ?? "", artUri: Uri.parse(musicDetails.coverImage ?? ""), ), ); } @override bool operator ==(Object other) => identical(this, other) || other is LazyAudioSource && runtimeType == other.runtimeType && index == other.index; @override int get hashCode => index.hashCode; } // 使用懒加载源初始化播放列表 final playlist = ConcatenatingAudioSource( children: allMusicDetails .asMap() .entries .map((entry) => LazyAudioSource(entry.value, entry.key)) .toList(), ); await player.setAudioSource(playlist, initialIndex: currentSongIndex.value); await player.setLoopMode(LoopMode.all);
3. 分离封面图片加载逻辑
封面图片的同步解析会额外增加AudioSource的创建耗时,可以暂时不在MediaItem中设置artUri,等到UI需要显示封面时再异步加载并本地缓存,避免阻塞播放列表的初始化流程。
内容的提问来源于stack exchange,提问作者Khyati Modi
相关产品推荐
相关产品推荐

