SuperAPI AI 工具集

nowplaying-pager-no-feedback-loop

编程与开发

查看项目

更新于 10-17 16:16

技能介绍

用途

这个技能面向 Android 上“正在播放”界面的封面横向 pager:它需要同时跟随播放器(播放器切歌时自动滑到对应页),又能在用户滑动并停稳后驱动播放器(seek 到对应曲目)。两个方向互相监听对方的写入,如果处理不好会形成反馈循环——播放器切歌导致 pager 滑动,pager 停稳又反过来向播放器下发一次 seek,造成重复跳转或“滑一次跳两首”。

主要能力

  1. 用自有标志隔离程序化动画:pagerState.isScrollInProgress 对用户拖动和程序调用 animateScrollToPage 同为 true,不能用来判断“用户正在拖动”。资料改用自己维护的 isAnimatingFromPlayer,并用 try/finally 包住每次程序化滚动,避免 effect 被取消时标志残留为 true 而永久阻塞后续写入。
  2. 从 settledPage 分发 seek:currentPage 在拖动越过一半时就翻转、targetPage 会随甩动变化,二者都可能一次手势触发多次 seek;只监听 settledPage 并去重,比较时先跳过 isAnimatingFromPlayer 为真、越界、以及 settled 等于当前索引的情况,最后一条正是打断反馈循环的关键。
  3. 纯函数决策:computeSeekAction(newPage, currentOrderIndex) 用差值返回 NoOp/Next/Previous/Skip,放在不依赖 UI 工具包的文件里,可脱离界面测试。±1 走播放器自身的上一首/下一首以保留相邻切换的过渡机制,跨度更大则走 seek-by-index。
  4. 后退滑动专用命令:普通 previous 通常带“已播放超过阈值则重播当前曲”的规则,后退半分钟会变成重播并让 pager 弹回;因此需要单独的“跳到上一项”命令,而不是修改原有 previous 的语义。
  5. 随机播放下的索引转换:页面索引是播放顺序,引擎 seek-by-index 是时间线顺序,随机模式下是排列关系;远距离跳转需走 getUnshuffledIndex 之类的入口做转换,±1 分支不受影响。
  6. 用队列实际存储的 id 推导页面:引擎可能拿到带前缀或缓存键的装饰性 media id,直接与队列普通 id 比较会失配、pager 停在 0 页;deriveOrderIndex 用 indexOfLast 匹配并以 coerceAtLeast(0) 兜底。同曲多份无法靠 id 区分,页面 key 需由 id 与索引组合保证唯一。
  7. 边界状态:队列缩短到当前页之后时,监听 size 并滚到最后一个索引;单曲循环开启时 next/previous 不移动,应通过 userScrollEnabled = !isRepeatOne && queue.isNotEmpty() 直接禁用滚动,而不是让用户空滑。

使用方式

以 Compose 的 LaunchedEffect + snapshotFlow 组织两个方向:一个 effect 监听 currentIndex 与 queue.size,在非用户拖动时用 animateScrollToPage 跟随;另一个 effect 监听 settledPage,distinctUntilChanged 后按守卫条件调用 dispatch(computeSeekAction(...))。所有程序化滚动都放进 isAnimatingFromPlayer 的 try/finally。验证可通过 grep 检查四个同步点(isScrollInProgress、animateScrollToPage、settledPage、scrollToPage)是否都被自有标志覆盖、决策文件是否不含 UI 工具包 import、播放器接口与各适配器是否都提供 seekToPrevious 与 seekToPreviousMediaItem;再按手动清单依次验证单页前进、自然播完、越过阈值后退、快速多页滑动、随机模式以及单曲循环。

适用场景

适用于 Compose 中播放器与分页控件双向绑定的“正在播放”封面浏览界面,尤其是需要处理随机播放、单曲循环、队列动态变化和相邻切换过渡动画的媒体类应用。

限制

资料未提供完整的可运行工程、依赖版本或安装命令,代码片段为改编示例;具体播放器接口命名(如 seekToPreviousMediaItem)、队列模型与随机索引转换函数需按项目实际实现。资料未涉及非 Android/Compose 平台、性能数据或收费信息。