用途 本技能针对音乐或视频应用里“从多个入口开始播放”的场景。搜索行、媒体库、歌单、专辑、分享链接、恢复会话各自有独立的条目类型和队列策略;如果为每个调用方各写一个入口,任何需要全局生效的规则(内容过滤、本地记录、时长回填、去重等)都会在至少一个入口上缺失,所以把这些入口合并成一个通用函数。
主要能力
- 类型规范化:通过泛型参数接收任意类型的条目,用 when 分支把 Track、SongEntity 等转换为统一的 Track;遇到无法识别的类型执行 else -> return,既不抛出异常,也不改动播放器。
- 策略路由:用 type 判别串决定队列填充方式,例如 SONG_CLICK、VIDEO_CLICK、SHARE 走单曲相关推荐,PLAYLIST_CLICK、ALBUM_CLICK、RADIO_CLICK 走歌单或专辑加载。
- 统一的播放控制策略:在改动播放器之前执行内容检查(例如 isExplicit 且未开启显式内容时提示并返回),被拦截的条目不会清空当前队列,当前正在播放的内容不受影响。
- 自动播放推导:playWhenReady = type != RECOVER_TRACK_QUEUE,恢复路径入队后不自动播放;避免用额外布尔参数让调用方组合出不存在的状态。
- 首项自启动:addMediaItemNotSet 在 player.mediaItemCount == 1 时调用 prepare 并设置 playWhenReady,避免向空播放器添加条目后停在就绪但未播放的状态;该判断不能无条件执行,否则每次追加都会重启播放。
- index 语义:表示“在来源中的位置”,用于歌单来源时定位用户点击的那一首,并在重新编目时跳过已入队的条目。
- suspend 约定:函数声明为 suspend,保证设置读取与可能的存储访问在入队前完成,防止调用方协程取消导致内容检查与入队发生竞争。
使用方式 函数签名示例:suspend fun <T> loadMediaItem(anyTrack: T, type: String, index: Int? = null)。条目规范化后,先执行前置策略检查,再执行 insertSong、clearMediaItems、addMediaItem 等副作用,最后按 type 分发到 getRelated 或 loadPlaylistOrAlbum。文档建议所有“每当一首曲目开始播放”都必须发生的副作用只放在此函数内,并且任何 UI 调用方都不应直接访问播放器。
校验方法
- 用 grep -rn "loadMediaItem(" --include='*.kt' . 列出全部播放来源。
- 在 UI 模块内用 grep 检索 player.addMediaItem( 或 player.setMediaItem(,确认没有调用方绕过入口(注意给 --include 加引号,避免部分 shell 提前展开通配符)。
- 用 grep 把 SONG_CLICK、PLAYLIST_CLICK、ALBUM_CLICK、RADIO_CLICK、SHARE、RECOVER 等常量与 when 分支对照,调用点出现但 when 中没有对应分支的常量即为无效来源。
- 在入口顶部临时加日志,逐一触发每个点击、长按菜单、分享链接和冷启动恢复,确认每个来源恰好打印一次;能播放却不打印的来源就是绕过入口的调用点。
适用场景 适用于 Kotlin 音频或视频应用中存在多个播放入口、需要统一执行播放策略与副作用、并希望恢复会话不自动播放的架构。
限制与注意事项
- String 判别串不具备穷尽性检查,拼写错误或新增来源未加分支时会静默失败(首项入队并播放,但队列不再填充),建议改用 sealed type 或 enum,保留 String 时须加 else 分支并明显记录日志。
- 内容检查的顺序是核心:必须位于首次修改播放器之前,否则被拒绝的点击会清空当前队列并中断播放。
- index 若不指向刚入队的条目,会导致整个队列与播放引擎错位。
- 该页面未提供完整的项目集成步骤、依赖版本、支持的平台或性能数据,这些内容暂未提供。