Flutter中QueryArtworkWidget播放歌曲时图片闪烁如何修复
Flutter on_audio_query 播放时封面闪烁修复方案
闪烁原因
realtimePlayingInfos 是高频刷新流,播放进度更新、状态回调都会触发其监听事件执行,直接在组件树中从该实例取歌曲ID传入QueryArtworkWidget会导致:
- 每次进度刷新都触发组件重建,即使歌曲ID没有变化
QueryArtworkWidget默认未开启旧封面保留逻辑,新封面加载过程中会先显示空白占位再切到封面,造成视觉上的闪烁- 未指定封面解码尺寸时,每次重建都会重新读取原图解码,IO和解码开销大,进一步加剧闪烁
修复步骤
- 拦截无意义重建:不要直接在build方法里从
realtimePlayingInfos取歌曲ID,单独维护一个currentPlayingId状态,仅在监听到播放歌曲ID真正发生变化(切歌)时才更新该状态,进度更新、播放状态变化这类不涉及歌曲切换的场景不触发封面组件重建 - 开启
QueryArtworkWidget旧封面保活:添加keepOldArtwork: true参数,新封面加载完成前始终保留上一帧已显示的封面,不会出现空白跳变 - 指定固定封面解码、缓存尺寸:根据组件实际展示大小设置
artworkWidth、artworkHeight以及对应缓存尺寸,避免每次重建都读取全尺寸原图解码,减少IO开销 - 固定解码格式:明确指定
format参数,避免系统每次自动选择解码格式导致的重绘差异
修复后参考代码
// 状态类中维护当前播放歌曲ID,初始值可设为null int? currentPlayingId; @override void initState() { super.initState(); // 监听播放信息流,仅在切歌时更新封面ID audioPlayer.playingInfoStream.listen((infos) { final newId = int.tryParse(infos.current?.audio.audio.metas.id ?? ''); if (newId != null && newId != currentPlayingId) { setState(() { currentPlayingId = newId; }); } }); } @override Widget build(BuildContext context) { // 封面组件 return ClipRRect( borderRadius: BorderRadius.circular(10), child: currentPlayingId == null ? Icon( Icons.music_note, color: Colors.white, size: 40, ) : QueryArtworkWidget( keepOldArtwork: true, artworkWidth: 80, // 替换为你实际需要的封面宽度 artworkHeight: 80, // 替换为你实际需要的封面高度 artworkCacheWidth: (80 * MediaQuery.of(context).devicePixelRatio).round(), artworkCacheHeight: (80 * MediaQuery.of(context).devicePixelRatio).round(), format: ArtworkFormat.JPEG, nullArtworkWidget: Icon( Icons.music_note, color: Colors.white, size: 40, ), id: currentPlayingId!, type: ArtworkType.AUDIO, ), ); }
注意:如果项目中使用了状态管理(Provider、Bloc、Riverpod等),可以将当前播放ID放到对应状态中管理,核心逻辑不变:只有切歌时才更新封面组件依赖的ID值。
内容的提问来源于stack exchange,提问作者Rohit Krishna
相关产品推荐
相关产品推荐

