该技能介绍的是一套关于播放位置持久化与恢复的实现要点,来源代码为 Kotlin 播放器逻辑。
用途:解决“保存用户听到哪里”时的成本差异问题。重保存会重写整个队列并把列表序列化到存储,通常在切歌、暂停、销毁等场景触发;轻保存只写两个小值(曲目 ID 与位置),每五秒执行一次。
主要能力与做法:文本提供两个保存形态的示例。重保存函数 mayBeSaveRecentSong 带 runBlocking 开关,在需要阻塞时同步完成写入,否则交给协程;轻保存函数 mayBeSaveRecentPosition 只读取当前曲目 ID 并调用 settings.saveRecentSong 写入位置。轻保存不另设定时器,而是复用已有的进度循环,在每 100 毫秒的循环中累计时间,满 5000 毫秒执行一次,代价是最坏丢失五秒位置。
文中列出的陷阱包括:重启进度循环前必须取消旧循环,否则每次恢复、内部播放器切换或缓冲结束都会泄漏一个循环,导致 UI 和位置写入成倍增加,可用循环内日志每秒行数是否恒定为十来验证;队列重建期间应跳过重保存,因为重建会清空列表并最后重新加入当前曲目,此时保存会得到不含当前曲目的队列,轻保存则因只写 id 与位置而不受影响;恢复路径必须先快照已保存位置再发出播放器命令,因为加载队列会触发切歌回调并重写存储;保存的曲目可能不在保存队列中,索引必须仍指向它,找不到时把当前曲目置于队首并把索引置零;入队后要 loadJob?.join() 等待加载再 seek,否则长队列下 seek 会静默失效;seek 之后要手动把恢复的值发布到暴露的状态流,因为此时没有播放,100 毫秒进度循环不会启动;时长同样需要在发布恢复位置时从元数据播种,并对后续每次写入加 newDuration.takeIf { it > 0L } ?: previous 保护,避免引擎尚未解析容器时的负哨兵值覆盖有效时长;重保存应使用一个函数体加阻塞开关,而不是两份实现,以免异步与阻塞版本漂移;位置应使用 contentPosition 而非 currentPosition,因为前者不含插入内容,后者包含;持久化受用户设置门控,关闭时没有存储队列,恢复必须是无操作而非用空 id 恢复。
使用方式与适用场景:面向 Kotlin 音乐播放器开发,在现有进度循环中接入轻保存、在生命周期边界接入重保存,并按文中顺序处理恢复流程。
限制:文本未给出完整项目结构、依赖版本、商店或价格信息;所述行为均来自该技能页面内容,具体实现需结合自身播放器状态模型。